mirror of
https://github.com/PretendoNetwork/website.git
synced 2026-08-06 10:13:05 -05:00
commit
705a52a641
2
.eslintignore
Normal file
2
.eslintignore
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# web javascript causes a lot of eslint warnings
|
||||
assets/js/*.js
|
||||
|
|
@ -3,7 +3,10 @@
|
|||
"node": true,
|
||||
"commonjs": true,
|
||||
"es6": true
|
||||
},
|
||||
},
|
||||
"globals": {
|
||||
"document": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2017
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
@font-face {
|
||||
font-family: 'icomoon';
|
||||
src: url('/assets/fonts/icomoon.eot?ybqupz');
|
||||
src: url('/assets/fonts/icomoon.eot?ybqupz#iefix') format('embedded-opentype'),
|
||||
url('/assets/fonts/icomoon.ttf?ybqupz') format('truetype'),
|
||||
url('/assets/fonts/icomoon.woff?ybqupz') format('woff'),
|
||||
url('/assets/fonts/icomoon.svg?ybqupz#icomoon') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
[class^="pretendo-icon-"], [class*=" pretendo-icon-"] {
|
||||
/* use !important to prevent issues with browser extensions that change fonts */
|
||||
font-family: 'icomoon' !important;
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 1;
|
||||
font-size: 1em;
|
||||
|
||||
/* Better Font Rendering =========== */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.pretendo-icon-pretendo-logo:before {
|
||||
content: "\e900";
|
||||
}
|
||||
45
assets/css/pretendo-auth.css
Normal file
45
assets/css/pretendo-auth.css
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
body.flex.center {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
body footer {
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
body footer .content {
|
||||
border-radius: 0;
|
||||
background-color: transparent;
|
||||
padding: 1em 0;
|
||||
box-shadow: none;
|
||||
width: 30rem;
|
||||
max-width: 100vw;
|
||||
}
|
||||
|
||||
/* login/register card */
|
||||
.card {
|
||||
background-color: white;
|
||||
box-shadow: 0 3px 10px 0px rgba(0, 0, 0, 0.07);
|
||||
width: 35rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
.card .content {
|
||||
padding: 0 3em 4em 3em;
|
||||
}
|
||||
.card .head {
|
||||
background-color: #673ab7;
|
||||
color: white;
|
||||
font-size: 1em;
|
||||
font-weight: normal;
|
||||
padding: 1.5em 2em;
|
||||
margin: 0;
|
||||
}
|
||||
.card .content .btnMargin {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 3em 0 0 0;
|
||||
}
|
||||
.card .content .lowText {
|
||||
text-align: right;
|
||||
color: #707070;
|
||||
}
|
||||
379
assets/css/pretendo-common.css
Normal file
379
assets/css/pretendo-common.css
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
/*******************************************************/
|
||||
/* copyrighted by pretendo. */
|
||||
/* website design by jipfr, mrjvs and benthehuman */
|
||||
/*******************************************************/
|
||||
|
||||
/* fonts */
|
||||
@import url('https://fonts.googleapis.com/css?family=Roboto:400,700');
|
||||
|
||||
/* setup */
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Roboto', Arial, Helvetica, sans-serif;
|
||||
font-weight: 400;
|
||||
background: #efefef;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
body.flex {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
body.flex .contentWrapper {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* common header */
|
||||
nav.navWrapper {
|
||||
background: #673db6;
|
||||
color: white;
|
||||
display: flex;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
justify-content: center;
|
||||
}
|
||||
nav.navWrapper .navItem {
|
||||
flex: 0;
|
||||
padding: 15px 20px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
text-decoration: none;
|
||||
font-size: 1em;
|
||||
cursor: pointer;
|
||||
align-self: stretch;
|
||||
}
|
||||
nav.navWrapper .navItem:hover, nav.navWrapper .navItem.active {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
background: rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
nav.navWrapper .navItem.brand {
|
||||
font-weight: 600;
|
||||
background: #5231a7;
|
||||
padding: 15px 40px;
|
||||
color: white;
|
||||
}
|
||||
nav.navWrapper .navBtn, nav.navWrapper .navBtnAlt {
|
||||
flex: 0;
|
||||
align-self: center;
|
||||
padding: 5px 30px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 1em;
|
||||
cursor: pointer;
|
||||
background-color: #512da8;
|
||||
border-radius: 5px;
|
||||
margin: 0 10px;
|
||||
box-shadow: 0 3px 10px 0px rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
nav.navWrapper .navBtnAlt {
|
||||
color: #3d1c8a;
|
||||
background-color: white;
|
||||
}
|
||||
nav.navWrapper .navBtn:hover {
|
||||
background-color: #52339b;
|
||||
}
|
||||
nav.navWrapper .navBtnAlt:hover {
|
||||
background-color: rgba(255, 255, 255, 0.745);
|
||||
color: #54359b;
|
||||
}
|
||||
nav.navWrapper .navItem:nth-last-child(2) {
|
||||
margin-right: 20px;
|
||||
}
|
||||
nav.navWrapper .navProfile {
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
}
|
||||
nav.navWrapper .navProfile img {
|
||||
border-radius: 50%;
|
||||
width: 2em; height: 2em;
|
||||
background-color: white;
|
||||
border: 1px solid rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
nav.navWrapper .navProfile p {
|
||||
padding: 0 0 0 10px;
|
||||
}
|
||||
nav.navWrapper .navSpread {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* mobile nav */
|
||||
nav.navWrapper .navItem.hamburger {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
@media screen and (max-width: 720px) {
|
||||
nav.navWrapper {
|
||||
flex-direction: column;
|
||||
box-shadow: 0 3px 10px 0px rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
nav.navWrapper .navItem:not(.brand) {
|
||||
display: none;
|
||||
}
|
||||
nav.navWrapper.open .navItem, nav.navWrapper .navItem.hamburger {
|
||||
display: block;
|
||||
}
|
||||
nav.navWrapper.open .navItem.navBtn, nav.navWrapper.open .navItem.navBtnAlt {
|
||||
padding: .5em 0;
|
||||
width: 12em;
|
||||
text-align: center;
|
||||
margin: .5em 0;
|
||||
}
|
||||
nav.navWrapper .navItem:nth-last-child(2) {
|
||||
margin-right: 0;
|
||||
}
|
||||
nav.navWrapper.open .navItem.navProfile {
|
||||
align-self: center;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
/* content wrapper */
|
||||
.contentWrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
nav.navWrapper ~ .contentWrapper:nth-child(2) {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
.contentWrapper .bgExtrude {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: #673db6;
|
||||
height: 10rem;
|
||||
z-index: 2;
|
||||
}
|
||||
.contentWrapper.bgLines::before, .contentWrapper.bgLines::after,
|
||||
.contentWrapper.bgLinesSmall::before, .contentWrapper.bgLinesSmall::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 100vh 0 0 200vw;
|
||||
border-color: transparent transparent transparent #673db6;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.contentWrapper.bgLines::after, .contentWrapper.bgLinesSmall::after {
|
||||
border-width: 0 0 100vh 200vw;
|
||||
border-color: transparent transparent #9575CD transparent;
|
||||
right: 0;
|
||||
left: auto;
|
||||
z-index: 2;
|
||||
}
|
||||
.contentWrapper.bgLinesSmall::after {
|
||||
border-width: 0 0 18vh 150vw;
|
||||
}
|
||||
.contentWrapper.bgLinesSmall::before {
|
||||
border-width: 20vh 0 0 150vw;
|
||||
}
|
||||
.contentWrapper > * {
|
||||
z-index: 3;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* footer */
|
||||
footer {
|
||||
background: #673db6;
|
||||
padding: 2em 1em;
|
||||
}
|
||||
footer .content {
|
||||
background: white;
|
||||
border-radius: 5px;
|
||||
padding: 1em;
|
||||
text-align: center;
|
||||
box-shadow: 0 3px 10px 0px rgba(0, 0, 0, 0.07);
|
||||
color: #707070;
|
||||
}
|
||||
footer .content span {
|
||||
color: black;
|
||||
}
|
||||
|
||||
/* big card */
|
||||
section.bigCardWrapper {
|
||||
padding: 20px;
|
||||
}
|
||||
section.bigCardWrapper .bigCard {
|
||||
max-width: 80vw;
|
||||
margin: auto;
|
||||
background-color: white;
|
||||
box-shadow: 0 3px 10px 0px rgba(0, 0, 0, 0.07);
|
||||
padding: 5vw 12vw;
|
||||
box-sizing: border-box;
|
||||
color: #707070;
|
||||
}
|
||||
section.bigCardWrapper .bigCard.lessPadding {
|
||||
padding: 4vw 5vw;
|
||||
}
|
||||
section.bigCardWrapper .bigCard.bigCardPartWrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
||||
/* text styles */
|
||||
.txt-highlight {
|
||||
color: #673db6;
|
||||
margin-bottom: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
.txt-title {
|
||||
color: #191919;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 15px;
|
||||
font-size: 2.5em;
|
||||
}
|
||||
.txt-title.small {
|
||||
font-size: 2em;
|
||||
}
|
||||
.txt-smallHeading {
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
color: #383838;
|
||||
}
|
||||
.txt-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* components - buttons */
|
||||
a.btn, a.btn-alt,
|
||||
a.btn:focus, a.btn-alt:focus,
|
||||
a.btn:hover, a.btn-alt:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
button, .btn, .btn-alt {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
font-family: 'Roboto';
|
||||
font-size: 1em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.btn, button {
|
||||
background: #673db6;
|
||||
color: white;
|
||||
padding: 12px 80px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 3px 12px rgba(0, 0, 0, 0.17);
|
||||
}
|
||||
.btn-alt {
|
||||
background: white;
|
||||
padding: 10px 45px;
|
||||
color: #673db6;
|
||||
border: 1px solid #673db6;
|
||||
box-shadow: 0 3px 12px rgba(0, 0, 0, 0.07);
|
||||
border-radius: 5px;
|
||||
}
|
||||
.btn:hover, button:hover, .btn-alt:hover {
|
||||
background: #553099;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* components - profiles */
|
||||
/* profiles */
|
||||
.cardProfiles {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.profile {
|
||||
min-width: 250px;
|
||||
width: 50%;
|
||||
max-width: 550px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
}
|
||||
.profileIcon {
|
||||
margin-right: 10px;
|
||||
width: 80px; height: 80px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.profileText {
|
||||
width: calc(100% - 130px);
|
||||
min-width: 200px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
.profileText h2 {
|
||||
margin: 0;
|
||||
}
|
||||
.profileText p {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/* components - inputs */
|
||||
|
||||
input::placeholder, textarea::placeholder {
|
||||
color: #bebebe;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
input[type="text"], input[type="password"], textarea {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 1em 2em;
|
||||
border-style: solid;
|
||||
border-color: rgb(165, 165, 165);
|
||||
border-width: 1px;
|
||||
border-radius: 8px;
|
||||
margin: 1em 0;
|
||||
font-family: 'Roboto', Arial, Helvetica, sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 3px 10px 0px rgba(0, 0, 0, 0.07);
|
||||
transition: border-color .1s;
|
||||
box-sizing: border-box;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 1em;
|
||||
margin: 2em 0 .2em .2em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
input[type="text"].hasLabel, input[type="password"].hasLabel {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: 12rem;
|
||||
}
|
||||
|
||||
input[type="text"]:focus, input[type="password"]:focus, textarea:focus {
|
||||
border-color: rgb(103, 61, 182);
|
||||
box-shadow: 0 3px 10px 0px rgba(103, 61, 182, 0.07);
|
||||
}
|
||||
|
||||
/* helper classes */
|
||||
.cont-flex {
|
||||
display: flex;
|
||||
}
|
||||
.flex-item {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
section.bigCardWrapper {
|
||||
padding: 0;
|
||||
padding-bottom: 3em;
|
||||
}
|
||||
section.bigCardWrapper .bigCard {
|
||||
max-width: 100vw;
|
||||
padding: 50px;
|
||||
}
|
||||
}
|
||||
15
assets/css/pretendo-contact.css
Normal file
15
assets/css/pretendo-contact.css
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
.input-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.input-container > * {
|
||||
flex: 1;
|
||||
}
|
||||
.input-container > *:first-child {
|
||||
margin-right: 3em;
|
||||
}
|
||||
@media screen and (max-width: 1000px) {
|
||||
.input-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
93
assets/css/pretendo-home.css
Normal file
93
assets/css/pretendo-home.css
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/* home header */
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
color: white;
|
||||
background: #673db6;
|
||||
padding: 5rem 1rem;
|
||||
}
|
||||
header hr {
|
||||
width: 175px;
|
||||
height: 2px;
|
||||
background: white;
|
||||
display: inline-block;
|
||||
border: 0;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
header h1 {
|
||||
font-size: 3.5em;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.25em;
|
||||
margin: 0;
|
||||
margin-bottom: 10px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
header h3 {
|
||||
font-weight: normal;
|
||||
max-width: 80%;
|
||||
display: inline-block;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* news cards */
|
||||
.smallCard {
|
||||
padding: 20px;
|
||||
border: 1px solid #9474cc; border-radius: 10px;
|
||||
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.07);
|
||||
position: relative;
|
||||
margin-left: 3em;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.smallCard h3 {
|
||||
font-size: 1.5em;
|
||||
margin: 0;
|
||||
}
|
||||
.smallCard p {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* specific */
|
||||
.smallCardWidth {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1050px) {
|
||||
.bigCard.cont-flex {
|
||||
flex-direction: column;
|
||||
}
|
||||
.bigCard > .flex-item {
|
||||
margin-bottom: 3em;
|
||||
}
|
||||
.smallCardWidth .smallCard {
|
||||
margin-left: 0;
|
||||
margin: 1em;
|
||||
}
|
||||
.bigCard.cont-flex > .cont-flex {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 888px) {
|
||||
.profile {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-width: 100%;
|
||||
}
|
||||
.smallCard {
|
||||
width: 100%;
|
||||
max-width: 250px;
|
||||
height: auto;
|
||||
}
|
||||
.bigCard.cont-flex > .cont-flex {
|
||||
flex-direction: column;
|
||||
}
|
||||
header h1 {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
}
|
||||
26
assets/css/pretendo-news.css
Normal file
26
assets/css/pretendo-news.css
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* news cards */
|
||||
.smallCard {
|
||||
padding: 2em;
|
||||
border: 1px solid rgb(165, 165, 165);
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.07);
|
||||
position: relative;
|
||||
margin: .5em;
|
||||
width: calc(50% - 1em );
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
}
|
||||
.smallCard h3 {
|
||||
font-size: 1.5em;
|
||||
margin: 0;
|
||||
}
|
||||
.smallCard a {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 720px) {
|
||||
.smallCard {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
72
assets/css/pretendo-pnid.css
Normal file
72
assets/css/pretendo-pnid.css
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
body .contentWrapper.userPage {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
margin: 10rem 0 7rem 0 !important; /*im sorry, I had to*/
|
||||
}
|
||||
body footer {
|
||||
padding: 0;
|
||||
box-shadow: 0 -3px 10px 0px rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
body footer .content {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* content card */
|
||||
.contentCard {
|
||||
background-color: white;
|
||||
box-shadow: 0 3px 10px 0px rgba(0, 0, 0, 0.07);
|
||||
box-sizing: border-box;
|
||||
color: #707070;
|
||||
width: 40rem;
|
||||
max-width: 100vw;
|
||||
padding: 3rem 4rem;
|
||||
}
|
||||
|
||||
/* aside navigation */
|
||||
nav.userNav {
|
||||
padding: 1em 3em 1em 1em;
|
||||
}
|
||||
nav.userNav .userNavProfile {
|
||||
text-align: center;
|
||||
}
|
||||
nav.userNav .userNavProfile::after {
|
||||
content: "";
|
||||
width: 10em;
|
||||
display: inline-block;
|
||||
height: 1px;
|
||||
background-color: rgba(0, 0, 0, 0.5);;
|
||||
}
|
||||
nav.userNav .userNavProfile img {
|
||||
width: 7em;
|
||||
height: 7em;
|
||||
background-color: white;
|
||||
border: 1px solid rgba(0, 0, 0, 0.5);
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
nav.userNav .userNavProfile .name {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
color: #353535;
|
||||
margin: .5em 1em 0 1em;
|
||||
}
|
||||
nav.userNav .links {
|
||||
padding: .7em 0;
|
||||
}
|
||||
nav.userNav .links .navItem {
|
||||
display: block;
|
||||
margin: .3em .5em;
|
||||
font-size: 1em;
|
||||
color: #707070;
|
||||
text-decoration: none;
|
||||
}
|
||||
nav.userNav .links .navItem:hover {
|
||||
color: #505050;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
}
|
||||
nav.userNav .links .navItem.active {
|
||||
color: #673ab7;
|
||||
font-weight: bold;
|
||||
}
|
||||
68
assets/css/pretendo-progress.css
Normal file
68
assets/css/pretendo-progress.css
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
section.bigCardWrapper.double {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
max-width: 80vw;
|
||||
margin: auto;
|
||||
}
|
||||
section.bigCardWrapper.double > .bigCard {
|
||||
flex: 1;
|
||||
padding: 1em 6em;
|
||||
margin: 0;
|
||||
}
|
||||
section.bigCardWrapper.double > .bigCard:first-child {
|
||||
margin-right: 3em;
|
||||
}
|
||||
|
||||
.listItem {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.listItem h2 {
|
||||
font-size: 1rem;
|
||||
color: #353535;
|
||||
margin: 1em 0 0 0;
|
||||
}
|
||||
.listItem p {
|
||||
margin: .2em 0 0 0;
|
||||
}
|
||||
|
||||
.listItem.state1::before, .listItem.state2::before, .listItem.state3::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: .2em;
|
||||
left: -1.5em;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
border-radius: 50%;
|
||||
background-color: #f57c7c; /* state 1: no support */
|
||||
}
|
||||
.listItem.state2::before {
|
||||
background-color: #e6ae65; /* state 2: partial support/bugged */
|
||||
}
|
||||
.listItem.state3::before {
|
||||
background-color: #58ef81; /* state 3: full support/working */
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1000px) {
|
||||
section.bigCardWrapper.double {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
section.bigCardWrapper.double > .bigCard {
|
||||
flex: 0;
|
||||
}
|
||||
section.bigCardWrapper.double > .bigCard:first-child {
|
||||
margin-right: 0;
|
||||
margin-bottom: 3em;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
section.bigCardWrapper.double {
|
||||
max-width: 100vw;
|
||||
margin: 0;
|
||||
}
|
||||
section.bigCardWrapper.double > .bigCard {
|
||||
padding: 50px;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
|
||||
/*
|
||||
|
||||
pretendo.css -
|
||||
main css file of the pretendo website
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
for home page only.
|
||||
sets the background
|
||||
|
||||
*/
|
||||
.hp-background {
|
||||
|
||||
-webkit-filter: brightness(30%) grayscale(100%);
|
||||
filter: brightness(30%) grayscale(100%);
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
homepage container for the title and stuff
|
||||
|
||||
*/
|
||||
.hp-container {
|
||||
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
text-align: left;
|
||||
left: 0%;
|
||||
z-index: 100;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
title text
|
||||
|
||||
*/
|
||||
.title {
|
||||
|
||||
font-family: "Overpass Mono", monospace;
|
||||
font-size: 500%;
|
||||
line-height: 0;
|
||||
color: white;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
main text
|
||||
|
||||
*/
|
||||
.text {
|
||||
|
||||
font-family: "Space Mono", monospace;
|
||||
font-size: 150%;
|
||||
color: white;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
font awesome icon container stylings
|
||||
|
||||
*/
|
||||
.icons {
|
||||
|
||||
margin-top: 10px;
|
||||
font-size: 1.75em;
|
||||
|
||||
}
|
||||
|
||||
.icons > a:not(:first-child) > .icon, .icons > .icon:not(:first-child) {
|
||||
|
||||
margin-left: 20px;
|
||||
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
||||
-webkit-transition: color 1s;
|
||||
transition: color 1s;
|
||||
color: white;
|
||||
border: 0;
|
||||
|
||||
}
|
||||
|
||||
.icon:hover {
|
||||
|
||||
color: black;
|
||||
|
||||
}
|
||||
|
||||
Binary file not shown.
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Generated by IcoMoon</metadata>
|
||||
<defs>
|
||||
<font id="icomoon" horiz-adv-x="1024">
|
||||
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
||||
<missing-glyph horiz-adv-x="1024" />
|
||||
<glyph unicode=" " horiz-adv-x="512" d="" />
|
||||
<glyph unicode="" glyph-name="pretendo-logo" d="M31.2 941.6l-27.2-18.4v-950.4l27.2-18.4c24-16.8 36.8-18.4 117.6-18.4h91.2v295.2c0 162.4 2.4 300.8 4.8 308 3.2 8.8 15.2 12.8 35.2 12.8 17.6 0 49.6 10.4 80 26.4 48 24 55.2 25.6 135.2 25.6 77.6 0 88.8-1.6 131.2-23.2 56.8-28.8 104-79.2 132-139.2 56-123.2-2.4-276.8-132-342.4-41.6-20.8-54.4-23.2-122.4-23.2-41.6 0-85.6 2.4-97.6 6.4l-22.4 5.6v-152h291.2c289.6 0 290.4 0 317.6 18.4l27.2 18.4v950.4l-54.4 36.8h-907.2l-27.2-18.4zM641.6 768c28-8.8 73.6-28.8 101.6-45.6 52-31.2 128.8-106.4 128.8-127.2 0-26.4-23.2-16.8-72.8 32-116.8 113.6-279.2 152.8-426.4 102.4-50.4-16.8-71.2-15.2-67.2 4.8 3.2 15.2 61.6 38.4 121.6 49.6 56.8 9.6 154.4 2.4 214.4-16zM596 692.8c22.4-5.6 59.2-20 82.4-32 48-24 121.6-91.2 121.6-111.2 0-26.4-18.4-22.4-54.4 12-52 49.6-78.4 66.4-136 85.6-58.4 20-141.6 22.4-198.4 4.8-52.8-16-67.2-15.2-67.2 3.2 0 14.4 36 33.6 84 43.2 35.2 8 130.4 4.8 168-5.6zM444 484.8c-30.4-13.6-72.8-58.4-83.2-87.2-4.8-12.8-8.8-41.6-8.8-64.8 0-89.6 73.6-154.4 168-147.2 92.8 6.4 149.6 72.8 142.4 167.2-4 52-16.8 75.2-65.6 114.4-24 20-37.6 24.8-79.2 26.4-30.4 1.6-58.4-1.6-73.6-8.8z" />
|
||||
</font></defs></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 4.4 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.8 MiB |
26
assets/js/auth.js
Normal file
26
assets/js/auth.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
function postAjax(url, data, success) {
|
||||
var params = (typeof data == 'string') ? data : Object.keys(data).map(function (k) {
|
||||
return encodeURIComponent(k) + '=' + encodeURIComponent(data[k])
|
||||
}).join('&');
|
||||
|
||||
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
|
||||
xhr.open('POST', url);
|
||||
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
xhr.send(params);
|
||||
return xhr;
|
||||
}
|
||||
|
||||
function login() {
|
||||
var xhr = postAjax('/api/v1/login', {
|
||||
email: document.getElementById('email_input').value,
|
||||
password: document.getElementById('password_input').value
|
||||
});
|
||||
xhr.onload = function () {
|
||||
console.log(xhr.responseText);
|
||||
response = JSON.parse(xhr.responseText);
|
||||
if (response.success === true) {
|
||||
location.pathname = '/pnid/dashboard';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/* eslint-env browser */
|
||||
|
||||
/*
|
||||
|
||||
index.js -
|
||||
the main javascript file
|
||||
|
||||
*/
|
||||
|
||||
// set some variables
|
||||
const bg = document.getElementById('hp-bg');
|
||||
let index = 0;
|
||||
const imageList = [ '/assets/images/bg1.gif', '/assets/images/bg2.gif' ];
|
||||
|
||||
// set the first image
|
||||
bg.src = imageList[index];
|
||||
index++;
|
||||
|
||||
setInterval(() => {
|
||||
|
||||
if (index === imageList.length) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
bg.src = imageList[index];
|
||||
|
||||
index++;
|
||||
}, 5000);
|
||||
3
assets/js/nav.js
Normal file
3
assets/js/nav.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
document.getElementById('navToggle').onclick = () => {
|
||||
document.getElementById('nav').classList.toggle('open');
|
||||
};
|
||||
|
|
@ -12,5 +12,9 @@
|
|||
},
|
||||
"secrets": {
|
||||
"session": "session secret here"
|
||||
},
|
||||
"recaptcha": {
|
||||
"siteKey": "abcd",
|
||||
"secretKey": "1234"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,26 @@ small commonly used utilities
|
|||
*/
|
||||
|
||||
// shows 404 template. takes express response object
|
||||
function sendDefault404(res) {
|
||||
function send404(res) {
|
||||
res.status(404).send('404');
|
||||
}
|
||||
|
||||
function templateReadyUser(req) {
|
||||
// normal user logged in
|
||||
const isLoggedIn = req.user ? req.user.role != 'admin' : false;
|
||||
const user = req.user;
|
||||
return {
|
||||
isLoggedIn,
|
||||
user
|
||||
};
|
||||
}
|
||||
|
||||
function getLocales() {
|
||||
return require('../locales/US_en.json');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sendDefault404
|
||||
send404,
|
||||
templateReadyUser,
|
||||
getLocales
|
||||
};
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
|
||||
admin-authentication.js -
|
||||
Middleware file for authentication checking
|
||||
|
||||
*/
|
||||
|
||||
// imports
|
||||
const apiHelper = require('../helpers/api');
|
||||
|
||||
// middleware to use if admin authentication is required
|
||||
function adminAuthNeeded(req, res, next) {
|
||||
if (req.isAuthenticated() && req.user.role && req.user.role === 'admin') {
|
||||
return next();
|
||||
} else {
|
||||
apiHelper.sendApiAuthError(res);
|
||||
}
|
||||
}
|
||||
|
||||
// middleware to use if authentication is optional
|
||||
function authOptional(req, res, next) {
|
||||
return next();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
adminAuthNeeded,
|
||||
authOptional
|
||||
};
|
||||
48
middleware/authentication.js
Normal file
48
middleware/authentication.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
|
||||
admin-authentication.js -
|
||||
Middleware file for authentication checking
|
||||
|
||||
*/
|
||||
|
||||
// imports
|
||||
const apiHelper = require('../helpers/api');
|
||||
|
||||
// middleware to use if admin authentication is required
|
||||
function adminAuthNeeded(req, res, next) {
|
||||
if (req.isAuthenticated() && req.user.role && req.user.role === 'admin') {
|
||||
return next();
|
||||
} else {
|
||||
apiHelper.sendApiAuthError(res);
|
||||
}
|
||||
}
|
||||
|
||||
// middleware to use if pnid auth authentication is required
|
||||
function pnidApiAuthNeeded(req, res, next) {
|
||||
if (req.isAuthenticated() && !req.user.role) { // having no role means its a normal account. only admin accounts have roles
|
||||
return next();
|
||||
} else {
|
||||
apiHelper.sendApiAuthError(res);
|
||||
}
|
||||
}
|
||||
|
||||
// middleware to use if pnid authentication is required
|
||||
function pnidAuthNeeded(req, res, next) {
|
||||
if (req.isAuthenticated() && !req.user.role) { // having no role means its a normal account. only admin accounts have roles
|
||||
return next();
|
||||
} else {
|
||||
res.redirect('/pnid/login');
|
||||
}
|
||||
}
|
||||
|
||||
// middleware to use if authentication is optional
|
||||
function authOptional(req, res, next) {
|
||||
return next();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
adminAuthNeeded,
|
||||
pnidAuthNeeded,
|
||||
pnidApiAuthNeeded,
|
||||
authOptional
|
||||
};
|
||||
|
|
@ -45,7 +45,7 @@ const blogPostSchema = new mongoose.Schema({
|
|||
date: {
|
||||
type: Date,
|
||||
default: () => {
|
||||
return new Date(moment(new Date(), 'YYYY-MM-DD'));
|
||||
return moment(moment().format('YYYY-MM-DD'));
|
||||
}
|
||||
},
|
||||
category: {
|
||||
|
|
@ -72,7 +72,7 @@ blogPostSchema.methods.postShortTemplate = function() {
|
|||
return {
|
||||
content: this.short,
|
||||
title: this.name,
|
||||
url: moment(this.meta.date, 'YYYY-MM-DD') + '/' + this.meta.slug
|
||||
url: moment(this.meta.date).format('YYYY-MM-DD') + '/' + this.meta.slug
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -85,13 +85,13 @@ blogPostSchema.statics.getPost = function(date, slug, callback) {
|
|||
'meta.slug': slug
|
||||
}, callback);
|
||||
};
|
||||
// not tested
|
||||
|
||||
blogPostSchema.statics.latestPostsShortTemlate = function(amount, callback) {
|
||||
blogPostModel.find({}).sort({'meta.date': 'desc'}).exec(function(err, posts) {
|
||||
if (err) return callback(err);
|
||||
let out = [];
|
||||
for (let i = 0, l = posts.length; i < ( amount+1 < l ? amount+1 : l); i++)
|
||||
out += posts[i].postShortTemplate();
|
||||
const out = [];
|
||||
for (let i = 0, l = posts.length; i < ( amount+1 < l ? amount : l); i++)
|
||||
out.push(posts[i].postShortTemplate());
|
||||
callback(err, out);
|
||||
});
|
||||
};
|
||||
|
|
|
|||
118
models/pnid.js
Normal file
118
models/pnid.js
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
|
||||
pnid.js -
|
||||
file containing the model for pretendo network id's
|
||||
|
||||
*/
|
||||
|
||||
// imports
|
||||
const mongoose = require('mongoose');
|
||||
const uniqueValidator = require('mongoose-unique-validator');
|
||||
const bcrypt = require('bcrypt');
|
||||
|
||||
// admin user database layout
|
||||
const PNIDSchema = new mongoose.Schema({
|
||||
email: {
|
||||
type: String,
|
||||
required: [true, 'Email is required.'],
|
||||
unique: true,
|
||||
trim: true,
|
||||
validate: [validateEmail, 'Please fill a valid email address']
|
||||
},
|
||||
email_validated: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// non hashed, gets hashed at save
|
||||
password: {
|
||||
type: String,
|
||||
required: [true, 'Password is required.'],
|
||||
minlength: [7, 'Password must be at-least 7 characters.'],
|
||||
maxlength: [256, 'Password cannot be more than 256 characters long.'],
|
||||
trim: true
|
||||
},
|
||||
pnid: {
|
||||
key: {
|
||||
type: String // not sure what this should be
|
||||
},
|
||||
pid: {
|
||||
type: String,
|
||||
unique: true
|
||||
}
|
||||
},
|
||||
consoles: []
|
||||
});
|
||||
|
||||
function validateEmail(email) {
|
||||
// eslint throws "unnecesary character escape"
|
||||
const re = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/; // eslint-disable-line
|
||||
return re.test(email);
|
||||
}
|
||||
|
||||
PNIDSchema.plugin(uniqueValidator, {message: '{PATH} already in use.'});
|
||||
|
||||
// hashing password
|
||||
PNIDSchema.pre('save', function(next) {
|
||||
// only if modified
|
||||
if (!this.isModified('password')) {
|
||||
return next();
|
||||
}
|
||||
// hashing
|
||||
const primaryhash = PNIDModel.hashPasswordPrimary(this.get('password'), this.get('pnid.pid'));
|
||||
bcrypt.hash(primaryhash, 10, (err, hash) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
this.set('password', hash);
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
PNIDSchema.statics.findByEmail = function(email) {
|
||||
return this.model('pnid').findOne({
|
||||
email
|
||||
});
|
||||
};
|
||||
|
||||
PNIDSchema.statics.hashPasswordPrimary = function(password, pid) {
|
||||
const buff1 = require('python-struct').pack('<I', pid);
|
||||
const buff2 = Buffer.from(password).toString('ascii');
|
||||
|
||||
const unpacked = new Buffer(bufferToHex(buff1) + '\x02eCF' + buff2, 'ascii');
|
||||
const hashed = require('crypto').createHash('sha256').update(unpacked).digest().toString('hex');
|
||||
|
||||
return hashed;
|
||||
};
|
||||
|
||||
function bufferToHex(buff) {
|
||||
let result = '';
|
||||
const arr = buff.toString('hex').match(/.{1,2}/g);
|
||||
for (let i=0;i<arr.length;i++) {
|
||||
const char = arr[i];
|
||||
result += String.fromCharCode(parseInt(char, 16));
|
||||
}
|
||||
result.replace(/\\/g, '\');
|
||||
return result;
|
||||
}
|
||||
|
||||
PNIDSchema.statics.generatePID = async function() {
|
||||
// Quick, dirty fix for PIDs
|
||||
const pid = Math.floor(Math.random() * (4294967295 - 1000000000) + 1000000000);
|
||||
const does_pid_inuse = await PNIDModel.findOne({
|
||||
'pnid.pid': pid
|
||||
});
|
||||
|
||||
if (does_pid_inuse) {
|
||||
return '' + await PNIDModel.generatePID();
|
||||
}
|
||||
|
||||
return '' + pid;
|
||||
};
|
||||
|
||||
const PNIDModel = mongoose.model('pnid', PNIDSchema);
|
||||
|
||||
module.exports = {
|
||||
PNIDModel,
|
||||
PNIDSchema
|
||||
};
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
|
|
@ -1186,6 +1186,11 @@
|
|||
"promise": "7.3.1"
|
||||
}
|
||||
},
|
||||
"express-recaptcha": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/express-recaptcha/-/express-recaptcha-4.0.3.tgz",
|
||||
"integrity": "sha512-DUNGjloA7pDeTT//CP0Dv/gZmYU+Nv/ZL/KPHKsNknI2m1epFTc9BFR/oDdmsP1pklNJEZ4wQtDoeaiFYZK2hw=="
|
||||
},
|
||||
"express-session": {
|
||||
"version": "1.15.6",
|
||||
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.15.6.tgz",
|
||||
|
|
@ -1650,6 +1655,11 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
|
||||
},
|
||||
"long": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
|
||||
"integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s="
|
||||
},
|
||||
"longest": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
|
||||
|
|
@ -2172,6 +2182,14 @@
|
|||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
||||
"dev": true
|
||||
},
|
||||
"python-struct": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/python-struct/-/python-struct-1.0.6.tgz",
|
||||
"integrity": "sha512-r40v2MDFZKNBECMuo/oih6wInNEFXX0gmQgCJH4R7VULJsQDwcE95004r7A8iy1tDipgcZDyF8H6Tc2bhJdRZQ==",
|
||||
"requires": {
|
||||
"long": "3.2.0"
|
||||
}
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
|
||||
|
|
|
|||
|
|
@ -21,12 +21,14 @@
|
|||
"connect-mongo": "^2.0.1",
|
||||
"express": "^4.16.2",
|
||||
"express-handlebars": "^3.0.0",
|
||||
"express-recaptcha": "^4.0.3",
|
||||
"express-session": "^1.15.6",
|
||||
"moment": "^2.22.2",
|
||||
"mongoose": "^5.3.2",
|
||||
"mongoose-unique-validator": "^2.0.2",
|
||||
"passport": "^0.4.0",
|
||||
"passport-local": "^1.0.0",
|
||||
"python-struct": "^1.0.6",
|
||||
"showdown": "^1.8.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -10,12 +10,14 @@ const LocalStrategy = require('passport-local').Strategy;
|
|||
const passport = require('passport');
|
||||
const bcrypt = require('bcrypt');
|
||||
const adminUserModel = require('./models/admin-user').adminUserModel;
|
||||
const PNIDModel = require('./models/pnid').PNIDModel;
|
||||
|
||||
// setup authentication
|
||||
module.exports = (app) => {
|
||||
app.use(passport.initialize());
|
||||
app.use(passport.session());
|
||||
passport.use('adminUserStrategy', new LocalStrategy(
|
||||
|
||||
(username, password, done) => {
|
||||
// find user in database
|
||||
adminUserModel.findByUsername(username).then((user) => {
|
||||
|
|
@ -42,14 +44,57 @@ module.exports = (app) => {
|
|||
});
|
||||
}
|
||||
));
|
||||
passport.use('PNIDStrategy', new LocalStrategy({
|
||||
usernameField: 'email'
|
||||
}, (email, password, done) => {
|
||||
// find user in database
|
||||
PNIDModel.findByEmail(email).then((user) => {
|
||||
if (!user) {
|
||||
// user doesnt exist
|
||||
return done(null, false, {message: 'Incorrect email'});
|
||||
}
|
||||
bcrypt.compare(password, user.password, (err, res) => {
|
||||
if (err || !res) {
|
||||
// error comparing hashes
|
||||
// try primary hash on password and checking again.
|
||||
bcrypt.compare(PNIDModel.hashPasswordPrimary(password, user.pnid.pid), user.password, (err, res) => {
|
||||
if (err || !res) {
|
||||
// error comparing hashes
|
||||
// password hashed and non hashed both incorrect.
|
||||
return done(null, false, {message: 'Incorrect password'});
|
||||
}
|
||||
// password is correct, return user
|
||||
return done(null, user);
|
||||
});
|
||||
} else {
|
||||
// password is correct, return user
|
||||
return done(null, user);
|
||||
}
|
||||
});
|
||||
}).catch((err) => {
|
||||
if (err) {
|
||||
// error finding in database
|
||||
return done(null, false, {code: 500});
|
||||
}
|
||||
});
|
||||
}
|
||||
));
|
||||
|
||||
//Configuring app to have sessions, dont change since it would break everything
|
||||
passport.serializeUser(function(user, done) {
|
||||
done(null, user.id);
|
||||
});
|
||||
|
||||
//SERIOUSLY. DONT TOUCH THIS SPAGHETTI, IT TOOK ME FOREVER TO GET THIS TO WORK!!!!1!!
|
||||
passport.deserializeUser(function(id, done) {
|
||||
adminUserModel.findById(id, function(err, user) {
|
||||
done(err, user);
|
||||
if (err || !user) {
|
||||
PNIDModel.findById(id, function(err, user) {
|
||||
done(err, user);
|
||||
});
|
||||
} else {
|
||||
done(err, user);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ const router = require('express').Router();
|
|||
const passport = require('passport');
|
||||
const moment = require('moment');
|
||||
const apiHelper = require('../helpers/api');
|
||||
const adminUserMiddleware = require('../middleware/admin-authentication');
|
||||
const utilHelper = require('../helpers/util');
|
||||
const userMiddleware = require('../middleware/authentication');
|
||||
|
||||
// database models
|
||||
const adminUser = require('../models/admin-user');
|
||||
|
|
@ -45,6 +46,7 @@ router.get('/admin', (req, res) => {
|
|||
router.post('/admin/api/v1/login', passport.authenticate('adminUserStrategy'), function (req, res) {
|
||||
apiHelper.sendReturn(res, {
|
||||
username: req.user.username,
|
||||
locales: utilHelper.getLocales(),
|
||||
role: req.user.role ? req.user.role : undefined
|
||||
});
|
||||
});
|
||||
|
|
@ -67,7 +69,7 @@ router.post('/admin/api/v1/login', passport.authenticate('adminUserStrategy'), f
|
|||
* errors: Strings[messages]
|
||||
* }
|
||||
*/
|
||||
router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthNeeded, (req, res) => {
|
||||
router.post('/admin/api/v1/register', userMiddleware.adminAuthNeeded, (req, res) => {
|
||||
if (!req.body) {
|
||||
// no post body
|
||||
apiHelper.sendApiGenericError(res);
|
||||
|
|
@ -81,10 +83,10 @@ router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthNeeded, (req,
|
|||
});
|
||||
|
||||
// saving to database
|
||||
newUser.save().then(() => {
|
||||
newUser.save().then((user) => {
|
||||
apiHelper.sendReturn(res, {
|
||||
username: req.user.username,
|
||||
role: req.user.role ? req.user.role : undefined
|
||||
username: user.username,
|
||||
role: user.role ? user.role : undefined
|
||||
});
|
||||
return;
|
||||
}).catch((rejection) => {
|
||||
|
|
@ -109,7 +111,7 @@ router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthNeeded, (req,
|
|||
* errors: Strings[messages]
|
||||
* }
|
||||
*/
|
||||
router.post('/admin/api/v1/removeadmin', adminUserMiddleware.adminAuthNeeded, (req, res) => {
|
||||
router.post('/admin/api/v1/removeadmin', userMiddleware.adminAuthNeeded, (req, res) => {
|
||||
if (!req.body) {
|
||||
// no post body
|
||||
apiHelper.sendApiGenericError(res);
|
||||
|
|
@ -136,7 +138,7 @@ router.post('/admin/api/v1/removeadmin', adminUserMiddleware.adminAuthNeeded, (r
|
|||
* errors: Strings[messages]
|
||||
* }
|
||||
*/
|
||||
router.get('/admin/api/v1/listadmins', adminUserMiddleware.adminAuthNeeded, (req, res) => {
|
||||
router.get('/admin/api/v1/listadmins', userMiddleware.adminAuthNeeded, (req, res) => {
|
||||
adminUser.adminUserModel.find({}, (err, admins) => {
|
||||
// TODO format exception so it doesnt have a huge list of errors
|
||||
if (err) return apiHelper.sendApiError(res, 500, [err]);
|
||||
|
|
@ -167,7 +169,7 @@ router.get('/admin/api/v1/listadmins', adminUserMiddleware.adminAuthNeeded, (req
|
|||
* errors: Strings[messages]
|
||||
* }
|
||||
*/
|
||||
router.get('/admin/api/v1/check', adminUserMiddleware.authOptional, (req, res) => {
|
||||
router.get('/admin/api/v1/check', userMiddleware.authOptional, (req, res) => {
|
||||
apiHelper.sendReturn(res, {
|
||||
isAuthed: req.user ? true : false,
|
||||
role: req.user ? (req.user.role ? req.user.role : undefined) : undefined
|
||||
|
|
@ -185,7 +187,7 @@ router.get('/admin/api/v1/check', adminUserMiddleware.authOptional, (req, res) =
|
|||
* errors: Strings[messages]
|
||||
* }
|
||||
*/
|
||||
router.get('/admin/api/v1/logout', adminUserMiddleware.adminAuthNeeded, (req, res) => {
|
||||
router.get('/admin/api/v1/logout', userMiddleware.adminAuthNeeded, (req, res) => {
|
||||
req.logout();
|
||||
apiHelper.sendReturn(res, {});
|
||||
});
|
||||
|
|
@ -210,7 +212,7 @@ router.get('/admin/api/v1/logout', adminUserMiddleware.adminAuthNeeded, (req, re
|
|||
* errors: Strings[messages]
|
||||
* }
|
||||
*/
|
||||
router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthNeeded, function (req, res) {
|
||||
router.post('/admin/api/v1/newpost', userMiddleware.adminAuthNeeded, function (req, res) {
|
||||
|
||||
if (!req.body) return apiHelper.sendApiGenericError(res);
|
||||
|
||||
|
|
@ -233,7 +235,7 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthNeeded, functi
|
|||
// saving post to database
|
||||
newBlogPost.save().then((post) => {
|
||||
apiHelper.sendReturn(res, {
|
||||
url: moment(post.meta.date, 'YYYY-MM-DD') + '/' + post.meta.slug
|
||||
url: moment(post.meta.date).format('YYYY-MM-DD') + '/' + post.meta.slug
|
||||
});
|
||||
}).catch((rejection) => {
|
||||
// TODO format exception so it doesnt have a huge list of errors
|
||||
|
|
@ -262,7 +264,7 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthNeeded, functi
|
|||
* errors: Strings[messages]
|
||||
* }
|
||||
*/
|
||||
router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthNeeded, function (req, res) {
|
||||
router.post('/admin/api/v1/editpost', userMiddleware.adminAuthNeeded, function (req, res) {
|
||||
|
||||
if (!req.body) return apiHelper.sendApiGenericError(res);
|
||||
|
||||
|
|
@ -299,7 +301,7 @@ router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthNeeded, funct
|
|||
* errors: Strings[messages]
|
||||
* }
|
||||
*/
|
||||
router.post('/admin/api/v1/newauthor', adminUserMiddleware.adminAuthNeeded, function (req, res) {
|
||||
router.post('/admin/api/v1/newauthor', userMiddleware.adminAuthNeeded, function (req, res) {
|
||||
|
||||
if (!req.body) return apiHelper.sendApiGenericError(res);
|
||||
|
||||
|
|
@ -340,7 +342,7 @@ router.post('/admin/api/v1/newauthor', adminUserMiddleware.adminAuthNeeded, func
|
|||
* errors: Strings[messages]
|
||||
* }
|
||||
*/
|
||||
router.post('/admin/api/v1/editauthor', adminUserMiddleware.adminAuthNeeded, function (req, res) {
|
||||
router.post('/admin/api/v1/editauthor', userMiddleware.adminAuthNeeded, function (req, res) {
|
||||
|
||||
if (!req.body) return apiHelper.sendApiGenericError(res);
|
||||
|
||||
|
|
@ -377,7 +379,7 @@ router.post('/admin/api/v1/editauthor', adminUserMiddleware.adminAuthNeeded, fun
|
|||
* errors: Strings[messages]
|
||||
* }
|
||||
*/
|
||||
router.post('/admin/api/v1/newprogress', adminUserMiddleware.adminAuthNeeded, function (req, res) {
|
||||
router.post('/admin/api/v1/newprogress', userMiddleware.adminAuthNeeded, function (req, res) {
|
||||
|
||||
if (!req.body) return apiHelper.sendApiGenericError(res);
|
||||
|
||||
|
|
@ -429,7 +431,7 @@ router.post('/admin/api/v1/newprogress', adminUserMiddleware.adminAuthNeeded, fu
|
|||
* errors: Strings[messages]
|
||||
* }
|
||||
*/
|
||||
router.post('/admin/api/v1/editprogress', adminUserMiddleware.adminAuthNeeded, function (req, res) {
|
||||
router.post('/admin/api/v1/editprogress', userMiddleware.adminAuthNeeded, function (req, res) {
|
||||
|
||||
if (!req.body) return apiHelper.sendApiGenericError(res);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ file for handling routes regarding blog posts.
|
|||
|
||||
// imports
|
||||
const router = require('express').Router();
|
||||
const moment = require('moment');
|
||||
const apiHelper = require('../helpers/api');
|
||||
const utilHelper = require('../helpers/util');
|
||||
const blogPostModel = require('../models/blog-post').blogPostModel;
|
||||
|
|
@ -17,7 +18,7 @@ router.get('/news/:date/:title', (req, res) => {
|
|||
// date format YYYY-MM-DD
|
||||
if (/[0-9]{4}-[0-9]{2}-[0-9]{2}/.test(req.params.date) && /([a-z]|[0-9]|-)+/.test(req.params.title.toLowerCase())) {
|
||||
// params are correct format
|
||||
blogPostModel.getPost(new Date(req.params.date), req.params.title.toLowerCase(), (err, post) => {
|
||||
blogPostModel.getPost(moment(req.params.date), req.params.title.toLowerCase(), (err, post) => {
|
||||
// error exists or no post exists with the date and name
|
||||
if (err || !post) {
|
||||
console.log('error: ' + err + ' and post: ' + post);
|
||||
|
|
@ -28,7 +29,9 @@ router.get('/news/:date/:title', (req, res) => {
|
|||
post.postTemplate((err, postTemplate) => {
|
||||
if (err) return utilHelper.send404(res);
|
||||
res.render('post', {
|
||||
post: postTemplate
|
||||
post: postTemplate,
|
||||
user: utilHelper.templateReadyUser(req),
|
||||
locales: utilHelper.getLocales()
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -53,7 +56,10 @@ router.get('/news', (req, res) => {
|
|||
}
|
||||
|
||||
res.render('post-collection', {
|
||||
posts: postCollection
|
||||
posts: postCollection,
|
||||
user: utilHelper.templateReadyUser(req),
|
||||
locales: utilHelper.getLocales(),
|
||||
page: 'news'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,12 +8,17 @@ file for handling routes regarding contact
|
|||
// imports
|
||||
const router = require('express').Router();
|
||||
const apiHelper = require('../helpers/api');
|
||||
const utilHelper = require('../helpers/util');
|
||||
const config = require('../config.json');
|
||||
const https = require('https');
|
||||
|
||||
// display contact page
|
||||
router.get('/contact', (req, res) => {
|
||||
res.render('contact');
|
||||
res.render('contact', {
|
||||
user: utilHelper.templateReadyUser(req),
|
||||
locales: utilHelper.getLocales(),
|
||||
page: 'contact'
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -8,10 +8,20 @@ for routes on the root path
|
|||
|
||||
// imports
|
||||
const router = require('express').Router();
|
||||
const utilHelper = require('../helpers/util');
|
||||
const blogPostModel = require('../models/blog-post').blogPostModel;
|
||||
|
||||
// display home page
|
||||
router.get('/', (req, res) => {
|
||||
res.render('home');
|
||||
// needs callback because mongoose is inconsistent
|
||||
blogPostModel.latestPostsShortTemlate(2, (err, result) => {
|
||||
res.render('home', {
|
||||
user: utilHelper.templateReadyUser(req),
|
||||
locales: utilHelper.getLocales(),
|
||||
posts: result,
|
||||
page: 'home'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// export the router
|
||||
|
|
|
|||
130
routes/pnid.js
Normal file
130
routes/pnid.js
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
|
||||
admin.js -
|
||||
file for handling admin api.
|
||||
|
||||
*/
|
||||
|
||||
// imports
|
||||
const router = require('express').Router();
|
||||
const passport = require('passport');
|
||||
const userMiddleware = require('../middleware/authentication');
|
||||
const apiHelper = require('../helpers/api');
|
||||
const utilHelper = require('../helpers/util');
|
||||
const config = require('../config.json');
|
||||
const Recaptcha = require('express-recaptcha').Recaptcha;
|
||||
const recaptcha = new Recaptcha(config.recaptcha.siteKey, config.recaptcha.secretKey);
|
||||
|
||||
// database models
|
||||
const PNID = require('../models/pnid');
|
||||
|
||||
// renders register page
|
||||
router.get('/pnid/register', recaptcha.middleware.render, (req, res) => {
|
||||
res.render('register', {
|
||||
captcha: res.recaptcha,
|
||||
locales: utilHelper.getLocales()
|
||||
});
|
||||
});
|
||||
// renders login page
|
||||
router.get('/pnid/login', (req, res) => {
|
||||
res.render('login', {
|
||||
locales: utilHelper.getLocales()
|
||||
});
|
||||
});
|
||||
// logout
|
||||
router.get('/pnid/logout', userMiddleware.pnidAuthNeeded, (req, res) => {
|
||||
req.logout();
|
||||
res.redirect('/');
|
||||
});
|
||||
// renders pnid dashboard
|
||||
router.get('/pnid/dashboard', userMiddleware.pnidAuthNeeded, (req, res) => {
|
||||
res.render('dashboard', {
|
||||
locales: utilHelper.getLocales(),
|
||||
user: utilHelper.templateReadyUser(req)
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
* /api/v1/login
|
||||
*
|
||||
* signs user in
|
||||
*
|
||||
* post {
|
||||
* email
|
||||
* password
|
||||
* }
|
||||
* return {
|
||||
* code: http code
|
||||
* success: boolean
|
||||
* username: undefined | string - only if login was successfull
|
||||
* role: undefined | string - role of user if login was successfull
|
||||
* errors: Strings[messages] - not yet :(
|
||||
* }
|
||||
*/
|
||||
// TODO make login somehow display errors in correct format.
|
||||
// middleware does the authentication work. this just returns a success
|
||||
router.post('/api/v1/login', passport.authenticate('PNIDStrategy'), function (req, res) {
|
||||
apiHelper.sendReturn(res, {
|
||||
email: req.user.email,
|
||||
email_validated: req.user.email_validated,
|
||||
pnid: req.user.pnid.key
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
* /api/v1/register
|
||||
*
|
||||
* registers a new admin user
|
||||
*
|
||||
* post {
|
||||
* username
|
||||
* password
|
||||
* }
|
||||
* return {
|
||||
* code: httpcode
|
||||
* success: boolean - true if register was successull
|
||||
* username: undefined | string - username if register was successfullW
|
||||
* errors: Strings[messages]
|
||||
* }
|
||||
*/
|
||||
router.post('/api/v1/register', recaptcha.middleware.verify, async (req, res) => {
|
||||
if (!req.body) {
|
||||
// no post body
|
||||
apiHelper.sendApiGenericError(res);
|
||||
return;
|
||||
}
|
||||
/*if (req.recaptcha.error) {
|
||||
apiHelper.sendApiError(res, 500, ['Captcha error']);
|
||||
return;
|
||||
}*/
|
||||
|
||||
const { email, password } = req.body;
|
||||
const newUser = new PNID.PNIDModel({
|
||||
email,
|
||||
password,
|
||||
pnid: {
|
||||
key: 'abcd',
|
||||
pid: await PNID.PNIDModel.generatePID()
|
||||
}
|
||||
});
|
||||
|
||||
// TODO verify password
|
||||
|
||||
// saving to database
|
||||
newUser.save().then((user) => {
|
||||
apiHelper.sendReturn(res, {
|
||||
email: user.email,
|
||||
email_validated: user.email_validated,
|
||||
pnid: user.pnid.key
|
||||
});
|
||||
return;
|
||||
}).catch((rejection) => {
|
||||
// TODO format exception so it doesnt have a huge list of errors
|
||||
console.log(rejection);
|
||||
apiHelper.sendApiError(res, 500, [rejection]);
|
||||
return;
|
||||
});
|
||||
});
|
||||
|
||||
// export the router
|
||||
module.exports = router;
|
||||
|
|
@ -9,7 +9,6 @@ file for handling routes regarding progress
|
|||
const router = require('express').Router();
|
||||
const apiHelper = require('../helpers/api');
|
||||
const utilHelper = require('../helpers/util');
|
||||
const staticText = require('../static-text.json');
|
||||
const progressListModel = require('../models/progress-list').progressListModel;
|
||||
|
||||
// display progress
|
||||
|
|
@ -25,7 +24,9 @@ router.get('/progress', (req, res) => {
|
|||
res.render('progress', {
|
||||
games,
|
||||
backends,
|
||||
summary: staticText.progressSummary
|
||||
user: utilHelper.templateReadyUser(req),
|
||||
locales: utilHelper.getLocales(),
|
||||
page: 'progress'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
22
server.js
22
server.js
|
|
@ -29,6 +29,7 @@ connection.on('error', console.error.bind(console, 'connection error:'));
|
|||
|
||||
// setup express
|
||||
const app = express();
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({ extended: false }));
|
||||
app.use(session({
|
||||
secret: config.secrets.session,
|
||||
|
|
@ -49,11 +50,22 @@ app.use(session({
|
|||
passportconfig(app);
|
||||
|
||||
// handlebars templating setup
|
||||
app.engine('.hbs', handlebars({
|
||||
const hbsEngine = handlebars({
|
||||
extname: '.hbs',
|
||||
layoutsDir: 'views',
|
||||
partialsDir: 'views/partials'
|
||||
}));
|
||||
partialsDir: 'views/partials',
|
||||
helpers: {
|
||||
'if_eq': function(a, b, opts) {
|
||||
if(a == b) return opts.fn(this);
|
||||
else return opts.inverse(this);
|
||||
},
|
||||
'if_neq': function(a, b, opts) {
|
||||
if(a != b) return opts.fn(this);
|
||||
else return opts.inverse(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
app.engine('.hbs', hbsEngine);
|
||||
app.set('view engine', '.hbs');
|
||||
|
||||
// locations and routes setup
|
||||
|
|
@ -62,7 +74,8 @@ const locations = {
|
|||
posts: require('./routes/blog'),
|
||||
admin: require('./routes/admin'),
|
||||
contact: require('./routes/contact'),
|
||||
progress: require('./routes/progress')
|
||||
progress: require('./routes/progress'),
|
||||
pnid: require('./routes/pnid')
|
||||
};
|
||||
|
||||
// static files
|
||||
|
|
@ -73,6 +86,7 @@ app.use('/', locations.contact);
|
|||
app.use('/', locations.posts);
|
||||
app.use('/', locations.admin);
|
||||
app.use('/', locations.progress);
|
||||
app.use('/', locations.pnid);
|
||||
app.use((req, res) => {
|
||||
utilHelper.send404(res);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,8 +1,18 @@
|
|||
const mongoose = require('mongoose');
|
||||
// fix database deprecation warnings
|
||||
mongoose.set('useCreateIndex', true);
|
||||
mongoose.set('useNewUrlParser', true);
|
||||
// setup database connection
|
||||
mongoose.connect(require('./config.json').database.url);
|
||||
const connection = mongoose.connection;
|
||||
connection.on('error', console.error.bind(console, 'connection error:'));
|
||||
|
||||
const adminUser = require('./models/admin-user');
|
||||
|
||||
|
||||
const newUser = new adminUser.adminUserModel({
|
||||
username: 'admin',
|
||||
password: 'root'
|
||||
password: 'rootroot'
|
||||
});
|
||||
|
||||
newUser.save().then(() => {
|
||||
|
|
|
|||
231
views/admin.hbs
231
views/admin.hbs
|
|
@ -1,127 +1,134 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{{> head }}
|
||||
{{> head-common }}
|
||||
</head>
|
||||
<body>
|
||||
{{> navbar }}
|
||||
{{> nav-default }}
|
||||
<div class="contentWrapper bgLinesSmall">
|
||||
<div class="bgExtrude"></div>
|
||||
<section class="bigCardWrapper">
|
||||
<div class="bigCard">
|
||||
<h1 class="txt-title">login</h1>
|
||||
<form action="/admin/api/v1/login" method="POST">
|
||||
<input type="text" name="username">
|
||||
<input type="text" name="password">
|
||||
<button>submit login</button>
|
||||
</form>
|
||||
|
||||
<h1>Admin panel here</h1>
|
||||
<h2>register</h2>
|
||||
<form action="/admin/api/v1/register" method="POST">
|
||||
<input type="text" name="username">
|
||||
<input type="text" name="password">
|
||||
<button>submit register</button>
|
||||
</form>
|
||||
|
||||
<h2>login</h2>
|
||||
<form action="/admin/api/v1/login" method="POST">
|
||||
<input type="text" name="username">
|
||||
<input type="text" name="password">
|
||||
<button>submit login</button>
|
||||
</form>
|
||||
<div id="container">
|
||||
<h1 class="txt-title">register new admin</h1>
|
||||
<form action="/admin/api/v1/register" method="POST">
|
||||
<input type="text" name="username">
|
||||
<input type="text" name="password">
|
||||
<button>submit register</button>
|
||||
</form>
|
||||
|
||||
<h2>delete admin</h2>
|
||||
<form action="/admin/api/v1/removeadmin" method="POST">
|
||||
<p>id</p>
|
||||
<input type="text" name="id">
|
||||
<button>delete admin</button>
|
||||
</form>
|
||||
<h1 class="txt-title">delete admin</h1>
|
||||
<form action="/admin/api/v1/removeadmin" method="POST">
|
||||
<p>id</p>
|
||||
<input type="text" name="id">
|
||||
<button>delete admin</button>
|
||||
</form>
|
||||
|
||||
<h2>create blog post</h2>
|
||||
<form action="/admin/api/v1/newpost" method="POST">
|
||||
<p>content</p>
|
||||
<textarea name="content" cols="30" rows="10"></textarea>
|
||||
<p>short version</p>
|
||||
<textarea name="short" cols="30" rows="10"></textarea>
|
||||
<p>category</p>
|
||||
<input type="text" name="category">
|
||||
<p>title</p>
|
||||
<input type="text" name="title">
|
||||
<p>author id</p>
|
||||
<input type="text" name="author">
|
||||
<button>create post</button>
|
||||
</form>
|
||||
<h1 class="txt-title">new blogpost</h1>
|
||||
<form action="/admin/api/v1/newpost" method="POST">
|
||||
<p>content</p>
|
||||
<textarea name="content" cols="30" rows="10"></textarea>
|
||||
<p>short version</p>
|
||||
<textarea name="short" cols="30" rows="10"></textarea>
|
||||
<p>category</p>
|
||||
<input type="text" name="category">
|
||||
<p>title</p>
|
||||
<input type="text" name="title">
|
||||
<p>author id</p>
|
||||
<input type="text" name="author">
|
||||
<button>create post</button>
|
||||
</form>
|
||||
|
||||
<h2>edit blog post</h2>
|
||||
<form action="/admin/api/v1/editpost" method="POST">
|
||||
<p>content</p>
|
||||
<textarea name="content" cols="30" rows="10"></textarea>
|
||||
<p>short version</p>
|
||||
<textarea name="short" cols="30" rows="10"></textarea>
|
||||
<p>id</p>
|
||||
<input type="text" name="id">
|
||||
<p>category</p>
|
||||
<input type="text" name="category">
|
||||
<p>title</p>
|
||||
<input type="text" name="title">
|
||||
<p>author id</p>
|
||||
<input type="text" name="author">
|
||||
<button>edit post</button>
|
||||
</form>
|
||||
<h1 class="txt-title">edit blogpost</h1>
|
||||
<form action="/admin/api/v1/editpost" method="POST">
|
||||
<p>content</p>
|
||||
<textarea name="content" cols="30" rows="10"></textarea>
|
||||
<p>short version</p>
|
||||
<textarea name="short" cols="30" rows="10"></textarea>
|
||||
<p>id</p>
|
||||
<input type="text" name="id">
|
||||
<p>category</p>
|
||||
<input type="text" name="category">
|
||||
<p>title</p>
|
||||
<input type="text" name="title">
|
||||
<p>author id</p>
|
||||
<input type="text" name="author">
|
||||
<button>edit post</button>
|
||||
</form>
|
||||
|
||||
<h2>new author</h2>
|
||||
<form action="/admin/api/v1/newauthor" method="POST">
|
||||
<p>name</p>
|
||||
<input type="text" name="name">
|
||||
<p>description</p>
|
||||
<input type="text" name="description">
|
||||
<p>image link</p>
|
||||
<input type="text" name="image">
|
||||
<button>submit author</button>
|
||||
</form>
|
||||
<h1 class="txt-title">new blogpost author</h1>
|
||||
<form action="/admin/api/v1/newauthor" method="POST">
|
||||
<p>name</p>
|
||||
<input type="text" name="name">
|
||||
<p>description</p>
|
||||
<input type="text" name="description">
|
||||
<p>image link</p>
|
||||
<input type="text" name="image">
|
||||
<button>submit author</button>
|
||||
</form>
|
||||
|
||||
<h2>edit author</h2>
|
||||
<form action="/admin/api/v1/editauthor" method="POST">
|
||||
<p>id</p>
|
||||
<input type="text" name="id">
|
||||
<p>name</p>
|
||||
<input type="text" name="name">
|
||||
<p>description</p>
|
||||
<input type="text" name="description">
|
||||
<p>image link</p>
|
||||
<input type="text" name="image">
|
||||
<button>edit author</button>
|
||||
</form>
|
||||
<h1 class="txt-title">edit author info</h1>
|
||||
<form action="/admin/api/v1/editauthor" method="POST">
|
||||
<p>id</p>
|
||||
<input type="text" name="id">
|
||||
<p>name</p>
|
||||
<input type="text" name="name">
|
||||
<p>description</p>
|
||||
<input type="text" name="description">
|
||||
<p>image link</p>
|
||||
<input type="text" name="image">
|
||||
<button>edit author</button>
|
||||
</form>
|
||||
|
||||
<h2>new progress entry</h2>
|
||||
<form action="/admin/api/v1/newprogress" method="POST">
|
||||
<p>title</p>
|
||||
<input type="text" name="title">
|
||||
<p>description</p>
|
||||
<input type="text" name="description">
|
||||
<p>state</p>
|
||||
<p>0 - backend service<br>1 - no support<br>2 - partial support<br>3 - fully working</p>
|
||||
<input type="text" name="state">
|
||||
<button>submit progress</button>
|
||||
</form>
|
||||
<h1 class="txt-title">new progress entry</h1>
|
||||
<form action="/admin/api/v1/newprogress" method="POST">
|
||||
<p>title</p>
|
||||
<input type="text" name="title">
|
||||
<p>description</p>
|
||||
<input type="text" name="description">
|
||||
<p>state</p>
|
||||
<p>0 - backend service<br>1 - no support<br>2 - partial support<br>3 - fully working</p>
|
||||
<input type="text" name="state">
|
||||
<button>submit progress</button>
|
||||
</form>
|
||||
|
||||
<h2>edit progress entry</h2>
|
||||
<form action="/admin/api/v1/editprogress" method="POST">
|
||||
<p>id</p>
|
||||
<input type="text" name="id">
|
||||
<p>title</p>
|
||||
<input type="text" name="title">
|
||||
<p>description</p>
|
||||
<input type="text" name="description">
|
||||
<p>state</p>
|
||||
<p>0 - backend service<br>1 - no support<br>2 - partial support<br>3 - fully working</p>
|
||||
<input type="text" name="state">
|
||||
<button>edit progress</button>
|
||||
</form>
|
||||
<h1 class="txt-title">edit progress entry</h1>
|
||||
<form action="/admin/api/v1/editprogress" method="POST">
|
||||
<p>id</p>
|
||||
<input type="text" name="id">
|
||||
<p>title</p>
|
||||
<input type="text" name="title">
|
||||
<p>description</p>
|
||||
<input type="text" name="description">
|
||||
<p>state</p>
|
||||
<p>0 - backend service<br>1 - no support<br>2 - partial support<br>3 - fully working</p>
|
||||
<input type="text" name="state">
|
||||
<button>edit progress</button>
|
||||
</form>
|
||||
|
||||
<br>
|
||||
<a href="/admin/api/v1/listadmins">List of admin users</a>
|
||||
<br>
|
||||
<a href="/api/v1/listblog">List of blog posts</a>
|
||||
<br>
|
||||
<a href="/api/v1/listprogress">List of progress</a>
|
||||
<br>
|
||||
<a href="/api/v1/listauthors">List of authors</a>
|
||||
<br>
|
||||
<a href="/admin/api/v1/check">Check if logged in</a>
|
||||
<br>
|
||||
<a href="/admin/api/v1/logout">Logout</a>
|
||||
|
||||
{{> footer }}
|
||||
<br>
|
||||
<a href="/admin/api/v1/listadmins">List of admin users</a>
|
||||
<br>
|
||||
<a href="/api/v1/listblog">List of blog posts</a>
|
||||
<br>
|
||||
<a href="/api/v1/listprogress">List of progress</a>
|
||||
<br>
|
||||
<a href="/api/v1/listauthors">List of authors</a>
|
||||
<br>
|
||||
<a href="/admin/api/v1/check">Check if logged in</a>
|
||||
<br>
|
||||
<a href="/admin/api/v1/logout">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{{> footer-default }}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{{> head }}
|
||||
<body>
|
||||
{{> navbar }}
|
||||
|
||||
<h1>contact form</h1>
|
||||
<form action="/api/v1/sendmessage" method="POST">
|
||||
<p>content</p>
|
||||
<textarea name="message" cols="30" rows="10"></textarea>
|
||||
<p>subject</p>
|
||||
<input type="text" name="subject">
|
||||
<p>email</p>
|
||||
<input type="text" name="email">
|
||||
<button>send message</button>
|
||||
</form>
|
||||
|
||||
{{> footer }}
|
||||
{{> head-common }}
|
||||
<!-- page specific -->
|
||||
<link rel="stylesheet" href="/assets/css/pretendo-contact.css">
|
||||
</head>
|
||||
<body class="flex">
|
||||
{{> nav-default }}
|
||||
<div class="contentWrapper bgLinesSmall">
|
||||
<div class="bgExtrude"></div>
|
||||
<section class="bigCardWrapper">
|
||||
<div class="bigCard">
|
||||
<p class="txt-highlight">ERROR</p>
|
||||
<h1 class="txt-title">{{ locales.contact.title }}</h1>
|
||||
<form action="/api/v1/sendmessage" method="POST">
|
||||
<div class="input-container">
|
||||
<input type="text" name="email" placeholder="{{ locales.contact.email_placeholder }}">
|
||||
<input type="text" name="subject" placeholder="{{ locales.contact.subject_placeholder }}">
|
||||
</div>
|
||||
<textarea name="message" placeholder="{{ locales.contact.message_placeholder }}"></textarea>
|
||||
<div class="txt-center">
|
||||
<button class="btn">{{ locales.contact.button_text }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{{> footer-default }}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
19
views/dashboard.hbs
Normal file
19
views/dashboard.hbs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{{> head-common }}
|
||||
<!-- page specific -->
|
||||
<link rel="stylesheet" href="/assets/css/pretendo-pnid.css">
|
||||
</head>
|
||||
<body class="flex">
|
||||
{{> nav-default }}
|
||||
<div class="contentWrapper userPage">
|
||||
{{> nav-dashboard }}
|
||||
<section class="contentCard">
|
||||
<p class="txt-highlight">ERROR</p>
|
||||
<h1 class="txt-title small">ERROR</h1>
|
||||
</section>
|
||||
</div>
|
||||
{{> footer-default }}
|
||||
</body>
|
||||
</html>
|
||||
139
views/home.hbs
139
views/home.hbs
|
|
@ -1,46 +1,103 @@
|
|||
<!--
|
||||
|
||||
home.hbs -
|
||||
the front page of the pretendo website
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
|
||||
{{> head }}
|
||||
|
||||
<title>pretendo</title>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="hp-container">
|
||||
|
||||
<img id="hp-bg" class="hp-background" src="">
|
||||
|
||||
<div class="hp-container">
|
||||
|
||||
<h1 class="title"><i class="pretendo-icon-pretendo-logo"></i>pretendo</h1>
|
||||
|
||||
<div class="text">
|
||||
an accurate-as-possible server emulation project for<br>
|
||||
nintendo consoles that use nintendo network
|
||||
</div>
|
||||
|
||||
<div class="icons">
|
||||
|
||||
<a href="https://github.com/PretendoNetwork"><i class="fab fa-github-alt icon"></i></a>
|
||||
<a href="https://www.npmjs.com/search?q=%40pretendo"><i class="fab fa-npm icon"></i></a>
|
||||
<a href="https://discord.gg/rxekqVJ"><i class="fab fa-discord icon"></i></a>
|
||||
<a href="https://twitter.com/pretendonetwork"><i class="fab fa-twitter icon"></i></a>
|
||||
|
||||
</div>
|
||||
|
||||
<head>
|
||||
{{> head-common }}
|
||||
<!-- page specific -->
|
||||
<link rel="stylesheet" href="/assets/css/pretendo-home.css">
|
||||
</head>
|
||||
<body>
|
||||
{{> nav-default }}
|
||||
<div class="contentWrapper">
|
||||
<header>
|
||||
<h1>ERROR</h1>
|
||||
<hr>
|
||||
<h3>ERROR</h3>
|
||||
</header>
|
||||
</div>
|
||||
<div class="contentWrapper bgLines">
|
||||
<div class="bgExtrude"></div>
|
||||
<section class="bigCardWrapper">
|
||||
<div class="bigCard">
|
||||
<p class="txt-highlight">ERROR</p>
|
||||
<h1 class="txt-title">{{ locales.about.title }}</h1>
|
||||
<p>{{ locales.about.text }}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</body>
|
||||
|
||||
<script src="/assets/js/index.js" type="text/javascript"></script>
|
||||
<section class="bigCardWrapper">
|
||||
<div class="bigCard">
|
||||
<p class="txt-highlight">ERROR</p>
|
||||
<h1 class="txt-title">{{ locales.credits.title }}</h1>
|
||||
<div class="cardProfiles">
|
||||
<!-- profile -->
|
||||
<div class="profile">
|
||||
<img class="profileIcon" src="https://cdn.discordapp.com/avatars/117261997619412996/c0e34de348b8d45e7a16c0260173bc8c.webp?size=256">
|
||||
<div class="profileText">
|
||||
<h2 class="txt-smallHeading">RedDucks</h2>
|
||||
<p>Project owner, lead developer, very violent young man. Splatoon obsessed as well.</p>
|
||||
</div>
|
||||
</div><!--
|
||||
--><div class="profile">
|
||||
<img class="profileIcon" src="https://cdn.discordapp.com/avatars/117261997619412996/c0e34de348b8d45e7a16c0260173bc8c.webp?size=256">
|
||||
<div class="profileText">
|
||||
<h2 class="txt-smallHeading">RedDucks</h2>
|
||||
<p>Project owner, lead developer, very violent young man. Splatoon obsessed as well.</p>
|
||||
</div>
|
||||
</div><!--
|
||||
--><div class="profile">
|
||||
<img class="profileIcon" src="https://cdn.discordapp.com/avatars/117261997619412996/c0e34de348b8d45e7a16c0260173bc8c.webp?size=256">
|
||||
<div class="profileText">
|
||||
<h2 class="txt-smallHeading">RedDucks</h2>
|
||||
<p>Project owner, lead developer, very violent young man. Splatoon obsessed as well.</p>
|
||||
</div>
|
||||
</div><!--
|
||||
--><div class="profile">
|
||||
<img class="profileIcon" src="https://cdn.discordapp.com/avatars/117261997619412996/c0e34de348b8d45e7a16c0260173bc8c.webp?size=256">
|
||||
<div class="profileText">
|
||||
<h2 class="txt-smallHeading">RedDucks</h2>
|
||||
<p>Project owner, lead developer, very violent young man. Splatoon obsessed as well.</p>
|
||||
</div>
|
||||
</div><!--
|
||||
--><div class="profile">
|
||||
<img class="profileIcon" src="https://cdn.discordapp.com/avatars/117261997619412996/c0e34de348b8d45e7a16c0260173bc8c.webp?size=256">
|
||||
<div class="profileText">
|
||||
<h2 class="txt-smallHeading">RedDucks</h2>
|
||||
<p>Project owner, lead developer, very violent young man. Splatoon obsessed as well.</p>
|
||||
</div>
|
||||
</div><!--
|
||||
--><div class="profile">
|
||||
<img class="profileIcon" src="https://cdn.discordapp.com/avatars/117261997619412996/c0e34de348b8d45e7a16c0260173bc8c.webp?size=256">
|
||||
<div class="profileText">
|
||||
<h2 class="txt-smallHeading">RedDucks</h2>
|
||||
<p>Project owner, lead developer, very violent young man. Splatoon obsessed as well.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bigCardWrapper">
|
||||
<div class="bigCard lessPadding cont-flex">
|
||||
<div class="flex-item">
|
||||
<p class="txt-highlight">ERROR</p>
|
||||
<h1 class="txt-title">ERROR</h1>
|
||||
<p>ERROR</p>
|
||||
<button class="btn">ERROR</button>
|
||||
</div>
|
||||
<div class="cont-flex">
|
||||
{{#each posts }}
|
||||
<div class="smallCardWidth">
|
||||
<div class="smallCard">
|
||||
<h3 class="txt-smallHeading">{{ this.title }}</h3>
|
||||
<p>{{ this.content }}</p>
|
||||
<a href="/news/{{ this.url }}" class="btn-alt">ERROR</a>
|
||||
</div>
|
||||
</div>
|
||||
{{/each }}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{{> footer-default }}
|
||||
</body>
|
||||
</html>
|
||||
27
views/login.hbs
Normal file
27
views/login.hbs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{{> head-common }}
|
||||
<!-- page specific -->
|
||||
<link rel="stylesheet" href="/assets/css/pretendo-auth.css">
|
||||
<script src="/assets/js/auth.js" defer></script>
|
||||
</head>
|
||||
<body class="flex center">
|
||||
<div class="card">
|
||||
<h2 class="head">{{ locales.nav.brand }}</h2>
|
||||
<div class="content">
|
||||
<p class="txt-highlight">ERROR</p>
|
||||
<h1 class="txt-title small">{{ locales.login_card.title }}</h1>
|
||||
<form action="/api/v1/sendmessage" method="POST">
|
||||
<label for="email">{{ locales.login_card.email_text }}</label>
|
||||
<input type="text" class="hasLabel" id="email_input" name="email">
|
||||
<label for="email">{{ locales.login_card.password_text }}</label>
|
||||
<input type="password" class="hasLabel" id="password_input" name="password">
|
||||
</form>
|
||||
<button class="btn btnMargin" onclick="login()">{{ locales.login_card.button_text }}</button>
|
||||
<p class="lowText">ERROR <a href="#">ERROR</a></p>
|
||||
</div>
|
||||
</div>
|
||||
{{> footer-default }}
|
||||
</body>
|
||||
</html>
|
||||
5
views/partials/footer-default.hbs
Normal file
5
views/partials/footer-default.hbs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<footer>
|
||||
<div class="content">
|
||||
<p>{{ locales.footer.text }}</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<footer class="footer">
|
||||
<p>© 2018 Pretendo</p>
|
||||
</footer>
|
||||
6
views/partials/head-common.hbs
Normal file
6
views/partials/head-common.hbs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{{> metatags }}
|
||||
<title>ERROR</title>
|
||||
<!-- css files -->
|
||||
<link rel="stylesheet" href="/assets/css/pretendo-common.css">
|
||||
<!-- scripts -->
|
||||
<script src="/assets/js/nav.js" defer></script>
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="an accurate-as-possible server emulation project for nintendo network-enabled devices">
|
||||
|
||||
<link rel="icon" href="/assets/favicon.ico">
|
||||
<link rel="apple-touch-icon" href="/assets/favicon.ico">
|
||||
<link rel="mask-icon" href="/assets/images/pretendo-logo.svg">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Overpass+Mono|Space+Mono" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/assets/css/pretendo.css">
|
||||
<link rel="stylesheet" href="/assets/css/icons.css">
|
||||
|
||||
<script defer src="https://use.fontawesome.com/releases/v5.0.10/js/all.js" integrity="sha384-slN8GvtUJGnv6ca26v8EzVaR9DC58QEwsIk9q1QXdCU8Yu8ck/tL/5szYlBbqmS+" crossorigin="anonymous"></script>
|
||||
|
||||
4
views/partials/metatags.hbs
Normal file
4
views/partials/metatags.hbs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<!-- meta tags -->
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
12
views/partials/nav-dashboard.hbs
Normal file
12
views/partials/nav-dashboard.hbs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<nav class="userNav">
|
||||
<div class="userNavProfile">
|
||||
<img src="" alt="">
|
||||
<p class="name">Mrjvs</p>
|
||||
</div>
|
||||
<div class="links">
|
||||
<a class="navItem active" href="#">ERROR</a>
|
||||
<a class="navItem" href="#">ERROR</a>
|
||||
<a class="navItem" href="#">ERROR</a>
|
||||
<a class="navItem" href="#">ERROR</a>
|
||||
</div>
|
||||
</nav>
|
||||
18
views/partials/nav-default.hbs
Normal file
18
views/partials/nav-default.hbs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<nav class="navWrapper" id="nav">
|
||||
<a class="navItem brand{{#if_eq page 'home'}} active{{/if_eq}}" {{#if_neq page 'home'}}href="/"{{/if_neq}}>{{ locales.nav.brand }}</a>
|
||||
<a class="navItem{{#if_eq page 'news'}} active{{/if_eq}}" {{#if_neq page 'news'}}href="/news"{{/if_neq}}>{{ locales.nav.links.news }}</a>
|
||||
<a class="navItem{{#if_eq page 'progress'}} active{{/if_eq}}" {{#if_neq page 'progress'}}href="/progress"{{/if_neq}}>{{ locales.nav.links.progress }}</a>
|
||||
<a class="navItem{{#if_eq page 'contact'}} active{{/if_eq}}" {{#if_neq page 'contact'}}href="/contact"{{/if_neq}}>{{ locales.nav.links.contact }}</a>
|
||||
<div class="navSpread"></div>
|
||||
{{#if user.isLoggedIn }}
|
||||
<a class="navItem navProfile" href="/pnid/dashboard">
|
||||
<img src="#" alt="">
|
||||
<p>mrjvs@gmail.com</p>
|
||||
</a>
|
||||
<a class="navItem navBtn" href="/pnid/logout">logout</a>
|
||||
{{else}}
|
||||
<a class="navItem navBtnAlt" href="/pnid/login">{{ locales.nav.links.login }}</a>
|
||||
<a class="navItem navBtn" href="/pnid/register">{{ locales.nav.links.register }}</a>
|
||||
{{/if}}
|
||||
<a class="navItem hamburger" id="navToggle">ICON</a>
|
||||
</nav>
|
||||
|
|
@ -1 +0,0 @@
|
|||
|
||||
|
|
@ -1,7 +1,29 @@
|
|||
<h1>Latest posts</h1>
|
||||
{{#each posts }}
|
||||
<strong>{{ this.title }}</strong>
|
||||
<p>{{ this.content }}</p>
|
||||
<a href="{{ this.url }}">link</a>
|
||||
<br><br>
|
||||
{{/each}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{{> head-common }}
|
||||
<!-- page specific -->
|
||||
<link rel="stylesheet" href="/assets/css/pretendo-news.css">
|
||||
</head>
|
||||
<body class="flex">
|
||||
{{> nav-default }}
|
||||
<div class="contentWrapper bgLinesSmall">
|
||||
<div class="bgExtrude"></div>
|
||||
<section class="bigCardWrapper">
|
||||
<div class="bigCard lessPadding">
|
||||
<p class="txt-highlight">ERROR</p>
|
||||
<h1 class="txt-title">ERROR</h1><!--
|
||||
{{#each posts }}
|
||||
--><article class="smallCard">
|
||||
<h3 class="txt-smallHeading">{{ this.title }}</h3>
|
||||
<p>{{ this.content }}</p>
|
||||
<a class="btn-alt" href="/news/{{ this.url }}">ERROR</a>
|
||||
</article><!--
|
||||
{{/each}}
|
||||
-->
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{{> footer-default }}
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,22 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{{> head }}
|
||||
<body>
|
||||
{{> navbar }}
|
||||
|
||||
<h1>{{ post.title }}</h1>
|
||||
<p>{{ post.date }}</p>
|
||||
<p>{{ post.category }}</p>
|
||||
|
||||
<article>
|
||||
{{{ post.content }}}
|
||||
</article>
|
||||
|
||||
<p>{{ post.author.name }} - {{ post.author.description }}</p>
|
||||
<img src="{{ post.author.profilePicture }}">
|
||||
|
||||
{{> footer }}
|
||||
|
||||
{{> head-common }}
|
||||
<!-- page specific -->
|
||||
</head>
|
||||
<body class="flex">
|
||||
{{> nav-default }}
|
||||
<div class="contentWrapper bgLinesSmall">
|
||||
<div class="bgExtrude"></div>
|
||||
<section class="bigCardWrapper">
|
||||
<div class="bigCard">
|
||||
<p class="txt-highlight">{{ post.category }} — {{ post.date }}</p>
|
||||
<h1 class="txt-title">{{ post.title }}</h1>
|
||||
{{{ post.content }}}
|
||||
<div class="profile">
|
||||
<img class="profileIcon" src="{{ post.author.profilePicture }}">
|
||||
<div class="profileText">
|
||||
<h2 class="txt-smallHeading">{{ post.author.name }}</h2>
|
||||
<p>{{ post.author.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{{> footer-default }}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,44 @@
|
|||
<h1>progress summary</h1>
|
||||
<p>{{ summary }}</p>
|
||||
<br>
|
||||
<h2>game support</h2>
|
||||
{{#each games }}
|
||||
<strong>{{ this.title }}</strong>
|
||||
<p>{{ this.description }}</p>
|
||||
<p>state: {{ this.state }}</p>
|
||||
{{/each}}
|
||||
<br><br>
|
||||
<h2>backend support</h2>
|
||||
{{#each backends }}
|
||||
<strong>{{ this.title }}</strong>
|
||||
<p>{{ this.description }}</p>
|
||||
{{/each}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{{> head-common }}
|
||||
<!-- page specific -->
|
||||
<link rel="stylesheet" href="/assets/css/pretendo-progress.css">
|
||||
</head>
|
||||
<body class="flex">
|
||||
{{> nav-default }}
|
||||
<div class="contentWrapper bgLinesSmall">
|
||||
<div class="bgExtrude"></div>
|
||||
<section class="bigCardWrapper">
|
||||
<div class="bigCard">
|
||||
<p class="txt-highlight">ERROR</p>
|
||||
<h1 class="txt-title">ERROR</h1>
|
||||
<p>{{ summary }}</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="bigCardWrapper double">
|
||||
<div class="bigCard">
|
||||
<p class="txt-highlight">ERROR</p>
|
||||
<h1 class="txt-title">ERROR</h1>
|
||||
{{#each games }}
|
||||
<div class="listItem state{{ this.state }}">
|
||||
<h2>{{ this.title }}</h2>
|
||||
<p>{{ this.description }}</p>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="bigCard">
|
||||
<p class="txt-highlight">ERROR</p>
|
||||
<h1 class="txt-title">ERROR</h1>
|
||||
{{#each backends }}
|
||||
<div class="listItem">
|
||||
<h2>{{ this.title }}</h2>
|
||||
<p>{{ this.description }}</p>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{{> footer-default }}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
31
views/register.hbs
Normal file
31
views/register.hbs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{{> head-common }}
|
||||
<!-- page specific -->
|
||||
<link rel="stylesheet" href="/assets/css/pretendo-auth.css">
|
||||
<script src="/assets/js/auth.js" defer></script>
|
||||
</head>
|
||||
<body class="flex center">
|
||||
<div class="card">
|
||||
<h2 class="head">{{ locales.nav.brand }}</h2>
|
||||
<div class="content">
|
||||
<p class="txt-highlight">{{ locales.register_card.caption }}</p>
|
||||
<h1 class="txt-title small">{{ locales.register_card.title }}</h1>
|
||||
<form action="/api/v1/sendmessage" method="POST">
|
||||
<label for="email">{{ locales.register_card.email_text }}</label>
|
||||
<input type="text" class="hasLabel" id="email_input" name="email">
|
||||
<label for="email">{{ locales.register_card.username_text }}</label>
|
||||
<input type="text" class="hasLabel" id="username_input" name="username">
|
||||
<label for="email">{{ locales.register_card.password_text }}</label>
|
||||
<input type="password" class="hasLabel" id="password_input" name="password">
|
||||
<label for="email">{{ locales.register_card.password_confirm_text }}</label>
|
||||
<input type="password" class="hasLabel" id="password_confirm_input" name="confirm_password">
|
||||
</form>
|
||||
<button class="btn btnMargin" onclick="register()">ERROR</button>
|
||||
<p class="lowText">ERROR <a href="#">ERROR</a></p>
|
||||
</div>
|
||||
</div>
|
||||
{{> footer-default }}
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user