Compare commits

..

No commits in common. "667c0222e95184cddee6db9c9fecc54ed2ae6009" and "27198d31312c7a648edb1f6b218e732d63d62d70" have entirely different histories.

44 changed files with 933 additions and 1266 deletions

View file

@ -20,7 +20,7 @@
"browser": true
},
"files": [
"public/**"
"public/js/*"
]
}
]

View file

@ -60,11 +60,8 @@ Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn
- _id
- add support for transition around gravatar
- forum setup page rewrite and directly open a router
- login w/ email
- BETTER SETUP PAGE
### front-end
- text alling center body
- add a css file for CodeMirror in threads / send message ok
- old contents / titles add to forum interface
- categories page is need a update, thread count in category (?)
@ -73,19 +70,7 @@ Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn
- give admin button, not is admin
- edit user ++
- rewrite main page, list new messages
- thread.js unfuction only listener
#### css fix
- admin page to css file
threads:
<style>
.fa {
color: var(--main);
}
</style>
https://medium.com/@minhquocece/how-to-create-an-upload-avatar-feature-like-facebook-by-cropper-js-and-slider-879990fdce82
## Major Version History
- V4: Caching

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "akf-forum",
"version": "5.2.0",
"version": "5.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "akf-forum",
"version": "5.2.0",
"version": "5.1.0",
"license": "GPL-3.0-or-later",
"dependencies": {
"bcrypt": "^5.1.0",

View file

@ -1,6 +1,6 @@
{
"name": "akf-forum",
"version": "5.2.0",
"version": "5.1.0",
"description": "A Node.js based forum software",
"main": "index.js",
"scripts": {

215
public/css/common.css Normal file
View file

@ -0,0 +1,215 @@
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: Poppins;
min-height: 400px;
margin-bottom: 100px;
clear: both;
}
a {
text-decoration: none;
color: initial;
}
.header {
width: 100%;
padding: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
padding: 10px;
font-size: 28px;
color: var(--main);
font-weight: 900;
}
.logo>span {
color: var(--second);
}
.buttons {
padding: 0;
display: flex;
align-items: center;
}
.btn-primary {
color: var(--btn-clr-1);
background-color: var(--main);
padding: 10px 20px 10px 20px;
border-radius: 4px;
font-weight: 700;
margin: 10px;
cursor: pointer;
border: 2px solid var(--main);
}
.btn-danger {
color: var(--btn-clr-1);
background-color: var(--important);
padding: 0px 10px 0px 10px;
border-radius: 4px;
font-weight: 700;
margin: 10px;
cursor: pointer;
border: 2px solid var(--important);
}
.btn-outline-primary {
color: var(--main);
padding: 10px 20px 10px 20px;
border-radius: 4px;
font-weight: 700;
margin: 10px;
cursor: pointer;
border: 2px solid var(--borders);
}
.btn-primary:hover {
color: var(--main);
background-color: rgba(0, 0, 0, 0);
border: 2px solid var(--main);
}
.btn-outline-primary:hover {
border: 2px solid var(--main);
}
.btn-danger:hover {
background-color: var(--important);
border: 2px solid var(--important);
}
.menu {
width: 100%;
padding: 20px;
display: flex;
justify-content: space-around;
}
.menu-item {
padding: 10px;
font-weight: 700;
background-color: var(--second);
color: var(--menu-item);
border-radius: 5px;
width: 100%;
text-align: center;
margin: 0px 10px 0px 0px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.active-menu {
background-color: var(--main);
}
.menu-item:hover {
background-color: var(--main);
}
.admin-bar {
font-size: 15px;
color: var(--menu-item);
background: var(--main);
text-align: center;
}
div.avatar {
padding-left: 10px;
}
.avatar>img {
width: 30px;
height: 30px;
border-radius: 50%;
margin: auto;
}
.box-username {
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
font-weight: 700;
color: var(--main);
}
@media (max-width: 992px) {
.header {
flex-direction: column;
align-items: center;
}
.menu {
flex-direction: column;
}
.menu-item {
margin: 0px 10px 10px 0px;
}
}
@media (max-width: 480px) {
.btn-outline-primary {
width: 100%;
text-align: center;
}
.buttons {
flex-direction: column;
width: 100%;
}
.btn-primary {
width: 100%;
text-align: center;
}
}
/*
FOOTER
*/
select {
background: #ebebeb;
border: white;
padding: 8px 20px;
font-size: 16px;
font-family: inherit;
}
select option {
font-family: inherit;
width: 290px;
}
.footer {
width: 100%;
background-color: var(--main);
bottom: 0;
color: white;
display: flex;
position: fixed;
justify-content: space-between;
align-items: center;
}

View file

@ -0,0 +1,27 @@
.title {
color: var(--main);
font-weight: 700;
}
form {
display: flex;
flex-direction: column;
align-items: center;
max-width: 1000px;
margin: 0 auto;
}
.input {
padding: 8px 10px;
font-family: inherit;
display: block;
font-weight: 600;
color: var(--input-clr);
width: 100%;
margin-bottom: 10px;
border: 2px solid var(--borders);
}
.CodeMirror {
width: 100%;
}

26
public/css/login.css Normal file
View file

@ -0,0 +1,26 @@
.title {
color: var(--main);
font-weight: 700;
}
form {
display: flex;
align-items: center;
flex-direction: column;
max-width: 500px;
margin: 0 auto;
width: 100%;
padding: 8px;
}
.input {
padding: 8px 10px;
font-family: inherit;
display: block;
font-weight: 600;
color: var(--input-clr);
width: 100%;
margin-bottom: 10px;
border: 2px solid var(--borders);
}

34
public/css/messages.css Normal file
View file

@ -0,0 +1,34 @@
.date {
color: var(--second);
}
.message {
max-width: 800px;
box-shadow: 0 0 5px 0 var(--box-shadow);
margin: 10px auto;
padding: 20px;
display: flex;
gap: 10px;
position: relative;
}
.message .left {
text-align: center;
border-right: 2px solid var(--borders);
}
.message .left img {
width: 100px;
height: 100px;
border-radius: 50%;
margin-right: 5px;
}
.message .left .username a {
color: var(--t-username);
}
.content {
width: 70%;
color: var(--anti);
}

75
public/css/modal.css Normal file
View file

@ -0,0 +1,75 @@
form {
display: flex;
align-items: center;
flex-direction: column;
max-width: 500px;
margin: 0 auto;
width: 100%;
padding: 8px;
}
.input {
padding: 8px 10px;
font-family: inherit;
display: block;
font-weight: 600;
color: var(--input-clr);
width: 100%;
margin-bottom: 10px;
border: 2px solid var(--borders);
}
/* MODAL */
.forum-modal {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: #5b5b5bde;
}
.forum-modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 10px;
opacity: 0;
display: block;
animation: fadeIn 1s forwards;
}
.forum-modal.no-active {
display: none;
}
.forum-modal-close {
position: absolute;
top: 0;
right: 10px;
font-size: 36px;
color: var(--main);
cursor: pointer;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@media(max-width:760px) {
.forum-modal-content {
width: 95%;
}
}

41
public/css/pages.css Normal file
View file

@ -0,0 +1,41 @@
.pagination {
box-shadow: 0 0 5px 0 var(--box-shadow);
margin: 10px auto;
padding: 8px;
display: flex;
justify-content: space-between;
align-items: center;
max-width: 400px;
gap: 10px;
position: relative;
}
.pagination .back,
.pagination .after {
color: var(--second);
font-size: 26px;
cursor: pointer;
}
.pagination .numbers {
display: flex;
align-items: center;
gap: 5px;
}
.pagination .number {
color: var(--second);
font-size: 22px;
border: 0 0 5px var(--second);
padding: 8px;
border-radius: 2px;
font-weight: 600;
cursor: pointer;
margin: 8px;
}
.pagination .number.active {
color: var(--main);
font-weight: 700;
}

27
public/css/search.css Normal file
View file

@ -0,0 +1,27 @@
.title {
color: var(--main);
font-weight: 700;
}
form {
display: flex;
align-items: center;
flex-direction: column;
max-width: 500px;
margin: 20px auto;
width: 100%;
padding: 10px;
box-shadow: 0 0 5px 0 #b0b0b0;
}
.input {
padding: 8px 10px;
font-family: inherit;
display: block;
font-weight: 600;
color: var(--input-clr);
width: 100%;
margin-bottom: 10px;
border: 2px solid var(--borders);
}

26
public/css/setup.css Normal file
View file

@ -0,0 +1,26 @@
.title {
color: var(--main);
font-weight: 700;
}
form {
display: flex;
align-items: center;
flex-direction: column;
max-width: 500px;
margin: 0 auto;
width: 100%;
padding: 8px;
}
input {
padding: 8px 10px;
font-family: inherit;
display: block;
font-weight: 600;
color: var(--input-clr);
width: 100%;
margin-bottom: 10px;
border: 2px solid var(--borders);
}

179
public/css/thread.css Normal file
View file

@ -0,0 +1,179 @@
.title {
color: var(--input-clr);
font-weight: 700;
font-size: 36px;
}
.date {
color: var(--second);
}
.message {
max-width: 800px;
box-shadow: 0 0 5px 0 var(--box-shadow);
margin: 10px auto;
padding: 20px;
display: flex;
gap: 10px;
position: relative;
}
.message .left {
text-align: center;
border-right: 2px solid var(--borders);
}
.message .left img {
width: 100px;
height: 100px;
border-radius: 50%;
margin-right: 5px;
}
.message .left .username a {
color: var(--t-username);
}
.content {
width: 70%;
color: var(--anti);
}
.reactions {
position: absolute;
right: 20px;
bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.reactions div {
display: flex;
align-items: center;
gap: 5px;
padding: 4px;
color: var(--second);
cursor: pointer;
transition: color 0.3s ease;
}
.reactions div:hover {
color: var(--anti);
}
.reactions div i {
font-size: 22px;
}
.dots {
position: absolute;
right: 20px;
font-size: 22px;
top: 10px;
color: var(--second);
cursor: pointer;
}
.dots-menu {
position: absolute;
top: 50px;
right: 0;
background-color: var(--second);
width: 100px;
text-align: center;
display: none;
}
.active {
display: block;
}
.no-display {
display: none;
}
.dots-menu a {
display: block;
margin: 8px;
cursor: pointer;
}
.dots-menu a:hover:nth-child(1) {
color: var(--important);
}
.dots-menu a:hover:nth-child(2) {
color: var(--main);
}
/* Media Query */
@media(max-width:980px) {
.message {
margin: 10px 20px;
max-width: 100%;
flex-direction: column;
position: relative;
}
.message .left {
padding: 40px;
border: none;
border-bottom: 2px solid var(--borders);
}
.message .left img {
width: 50px;
height: 50px;
border-radius: 50%;
margin-right: 5px;
position: absolute;
left: 20px;
top: 20px;
}
.message .left .username {
position: absolute;
top: 20px;
left: 80px;
}
.message .date:nth-of-type(3) {
position: absolute;
right: 20px;
top: 20px;
}
.message .date:nth-of-type(2) {
position: absolute;
right: 20px;
top: 40px;
}
.dots {
position: absolute;
right: auto;
top: 70px;
left: 40px;
}
.dots-menu {
position: absolute;
left: 70px;
top: 60px;
width: 120px;
}
.active {
display: flex;
}
.content {
width: 50%;
}
}

38
public/css/threads.css Normal file
View file

@ -0,0 +1,38 @@
.threads {
width: 100%;
padding: 20px;
}
.threads-box {
width: 100%;
padding: 8px;
box-shadow: 0 0 5px 0 var(--box-shadow);
display: flex;
justify-content: space-between;
margin: 0px 0px 8px 0px;
cursor: pointer;
align-items: center;
}
.threads-box:hover {
background-color: var(--box-shadow);
}
.thread-box-title {
padding: 10px;
font-size: 18px;
font-weight: 700;
color: var(--anti);
}
.thread-box-title>span {
color: var(--important);
}
@media (max-width: 480px) {
.threads-box {
flex-direction: column;
}
}

39
public/css/user.css Normal file
View file

@ -0,0 +1,39 @@
.title {
color: var(--main);
font-weight: 700;
}
.content {
display: flex;
flex-direction: column;
box-shadow: 0 0 5px 0 var(--box-shadow);
max-width: 900px;
margin: 0 auto;
padding: 10px;
color: var(--anti);
}
.box {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0 auto;
max-width: 800px;
width: 100%;
}
.box-title {
font-weight: 400;
color: var(--anti);
}
.box-value {
font-weight: 300;
background-color: var(--main);
color: white;
font-size: 14px;
padding: 4px;
border-radius: 5px;
min-width: 50px;
text-align: center;
}

47
public/css/users.css Normal file
View file

@ -0,0 +1,47 @@
.users {
width: 100%;
padding: 20px;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
gap: 10px;
}
.user-box {
width: 100%;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 0 5px 0 var(--box-shadow);
max-width:500px;
}
.user-box-title {
padding: 10px;
margin: 8px;
font-weight: 500;
}
.user-box-title>a{
color: var(--anti);
}
.user-box-title>span {
color: var(--important);
}
.user-box-img {
width: 80px;
height: 80px;
margin: auto;
}
@media (max-width: 992px) {
.users {
display: block;
}
.user-box {
margin-bottom: 10px;
}
}

View file

@ -1,15 +0,0 @@
function editor( uniqueId, textarea = document.getElementById("textarea")) {
return new SimpleMDE({
autosave: {
enabled: true,
uniqueId,
delay: 1000,
},// width: 100%;
element: textarea,
spellChecker: false
});
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -56,15 +56,17 @@
<% } %>
</div>
</div>
<script>
const menuItems = document.getElementsByClassName("nav-link");
for (let i = 0; i < menuItems.length; i++)
for (let i = 0; i < menuItems.length; i++){console.log(menuItems[i].getAttribute("href"))
if (window.location.pathname.includes(menuItems[i].getAttribute("href"))) {
menuItems[i].classList.add("active");
break;
}
//break;
}}
</script>
</nav>

View file

@ -185,26 +185,6 @@ div.avatar {
color: var(--main);
}
.title {
color: var(--main);
}
.input {
padding: 8px 10px;
color: var(--input-clr);
width: 100%;
margin-bottom: 10px;
border: 2px solid var(--borders);
}
form.post {
display: flex;
flex-direction: column;
align-items: center;
max-width: 1000px;
margin: 0 auto;
}
@media (max-width: 992px) {
.header {
flex-direction: column;
@ -291,405 +271,3 @@ a {
margin-top: 25px;
margin-bottom: 125px;
}
/***********************************
PAGINATION
***********************************/
.pagination {
box-shadow: 0 0 5px 0 var(--box-shadow);
margin: 10px auto;
padding: 8px;
display: flex;
justify-content: space-between;
align-items: center;
max-width: 400px;
gap: 10px;
position: relative;
}
.pagination .back,
.pagination .after {
color: var(--second);
font-size: 26px;
cursor: pointer;
}
.pagination .numbers {
display: flex;
align-items: center;
gap: 5px;
}
.pagination .number {
color: var(--second);
font-size: 22px;
border: 0 0 5px var(--second);
padding: 8px;
border-radius: 2px;
font-weight: 600;
cursor: pointer;
margin: 8px;
}
.pagination .number.active {
color: var(--main);
font-weight: 700;
}
/************************************
Threads
*************************************/
.threads {
width: 100%;
padding: 20px;
}
.threads-box {
width: 100%;
padding: 8px;
box-shadow: 0 0 5px 0 var(--box-shadow);
display: flex;
justify-content: space-between;
margin: 0px 0px 8px 0px;
cursor: pointer;
align-items: center;
}
.threads-box:hover {
background-color: var(--box-shadow);
}
.thread-box-title {
padding: 10px;
font-size: 18px;
font-weight: 700;
color: var(--anti);
}
.thread-box-title>span {
color: var(--important);
}
@media (max-width: 480px) {
.threads-box {
flex-direction: column;
}
}
/*****
LOGIN / REGISTER
******/
form.login {
display: flex;
align-items: center;
flex-direction: column;
max-width: 500px;
margin: 0 auto;
padding: 8px;
}
/********
MESSAGE
********/
.message .date {
color: var(--second);
}
.message {
max-width: 800px;
box-shadow: 0 0 5px 0 var(--box-shadow);
margin: 10px auto;
padding: 20px;
display: flex;
gap: 10px;
position: relative;
}
.message .left {
text-align: center;
border-right: 2px solid var(--borders);
}
.message .left img {
width: 100px;
height: 100px;
border-radius: 50%;
margin-right: 5px;
}
.message .left .username a {
color: var(--t-username);
}
.message .content {
width: 70%;
color: var(--anti);
}
@media(max-width:980px) {
.message {
margin: 10px 20px;
max-width: 100%;
flex-direction: column;
position: relative;
}
.message .left {
padding: 40px;
border: none;
border-bottom: 2px solid var(--borders);
}
.message .left img {
width: 50px;
height: 50px;
border-radius: 50%;
margin-right: 5px;
position: absolute;
left: 20px;
top: 20px;
}
.message .left .username {
position: absolute;
top: 20px;
left: 80px;
}
.message .date:nth-of-type(3) {
position: absolute;
right: 20px;
top: 20px;
}
.message .date:nth-of-type(2) {
position: absolute;
right: 20px;
top: 40px;
}
.message .content {
width: 50%;
}
}
/************************************
SEARCH
***************************************/
.search form {
display: flex;
align-items: center;
flex-direction: column;
max-width: 500px;
margin: 20px auto;
width: 100%;
padding: 10px;
box-shadow: 0 0 5px 0 #b0b0b0;
}
/****************************************
USERS
*****************************************/
.users {
width: 100%;
padding: 20px;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
gap: 10px;
}
.user-box {
width: 100%;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 0 5px 0 var(--box-shadow);
max-width: 500px;
}
.user-box-title {
padding: 10px;
margin: 8px;
font-weight: 500;
}
.user-box-title>a {
color: var(--anti);
}
.user-box-title>span {
color: var(--important);
}
.user-box-img {
width: 80px;
height: 80px;
margin: auto;
}
@media (max-width: 992px) {
.users {
display: block;
}
.user-box {
margin-bottom: 10px;
}
}
/************************************
THREAD
*************************************/
.title {
color: var(--input-clr);
font-weight: 700;
font-size: 36px;
}
.reactions {
position: absolute;
right: 20px;
bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.reactions div {
display: flex;
align-items: center;
gap: 5px;
padding: 4px;
color: var(--second);
cursor: pointer;
transition: color 0.3s ease;
}
.reactions div:hover {
color: var(--anti);
}
.reactions div i {
font-size: 22px;
}
.dots {
position: absolute;
right: 20px;
font-size: 22px;
top: 10px;
color: var(--second);
cursor: pointer;
}
.dots-menu {
position: absolute;
top: 50px;
right: 0;
background-color: var(--second);
width: 100px;
text-align: center;
display: none;
}
.active {
display: block;
}
.no-display {
display: none;
}
.dots-menu a {
display: block;
margin: 8px;
cursor: pointer;
}
.dots-menu a:hover:nth-child(1) {
color: var(--important);
}
.dots-menu a:hover:nth-child(2) {
color: var(--main);
}
/* Media Query */
@media(max-width:980px) {
.dots {
position: absolute;
right: auto;
top: 70px;
left: 40px;
}
.dots-menu {
position: absolute;
left: 70px;
top: 60px;
width: 120px;
}
.active {
display: flex;
}
}
/******************************
USER
******************************/
.usercontent {
display: flex;
flex-direction: column;
box-shadow: 0 0 5px 0 var(--box-shadow);
max-width: 900px;
margin: 0 auto;
padding: 10px;
color: var(--anti);
}
.userbox {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0 auto;
max-width: 800px;
width: 100%;
}
.userbox-title {
font-weight: 400;
color: var(--anti);
}
.userbox-value {
font-weight: 300;
background-color: var(--main);
color: white;
font-size: 14px;
padding: 4px;
border-radius: 5px;
min-width: 50px;
text-align: center;
}

View file

@ -1,643 +0,0 @@
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: Poppins;
min-height: 400px;
margin-bottom: 100px;
clear: both;
}
a {
text-decoration: none;
color: initial;
}
.header {
width: 100%;
padding: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
padding: 10px;
font-size: 28px;
color: var(--main);
font-weight: 900;
}
.logo>span {
color: var(--second);
}
.buttons {
padding: 0;
display: flex;
align-items: center;
}
.btn-primary {
color: var(--btn-clr-1);
background-color: var(--main);
padding: 10px 20px 10px 20px;
border-radius: 4px;
font-weight: 700;
margin: 10px;
cursor: pointer;
border: 2px solid var(--main);
}
.btn-danger {
color: var(--btn-clr-1);
background-color: var(--important);
padding: 0px 10px 0px 10px;
border-radius: 4px;
font-weight: 700;
margin: 10px;
cursor: pointer;
border: 2px solid var(--important);
}
.btn-outline-primary {
color: var(--main);
padding: 10px 20px 10px 20px;
border-radius: 4px;
font-weight: 700;
margin: 10px;
cursor: pointer;
border: 2px solid var(--borders);
}
.btn-primary:hover {
color: var(--main);
background-color: rgba(0, 0, 0, 0);
border: 2px solid var(--main);
}
.btn-outline-primary:hover {
border: 2px solid var(--main);
}
.btn-danger:hover {
background-color: var(--important);
border: 2px solid var(--important);
}
.menu {
width: 100%;
padding: 20px;
display: flex;
justify-content: space-around;
}
.menu-item {
padding: 10px;
font-weight: 700;
background-color: var(--second);
color: var(--menu-item);
border-radius: 5px;
width: 100%;
text-align: center;
margin: 0px 10px 0px 0px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.active-menu {
background-color: var(--main);
}
.menu-item:hover {
background-color: var(--main);
}
.admin-bar {
font-size: 15px;
color: var(--menu-item);
background: var(--main);
text-align: center;
}
div.avatar {
padding-left: 10px;
}
.avatar>img {
width: 30px;
height: 30px;
border-radius: 50%;
margin: auto;
}
.box-username {
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
font-weight: 700;
color: var(--main);
}
.CodeMirror {
color: var(--input-clr);
background-color: var(--bs-body-bg);
}
.title {
color: var(--main);
}
.input {
padding: 8px 10px;
color: var(--input-clr);
width: 100%;
margin-bottom: 10px;
border: 2px solid var(--borders);
}
form.post {
display: flex;
flex-direction: column;
align-items: center;
max-width: 1000px;
margin: 0 auto;
}
@media (max-width: 992px) {
.header {
flex-direction: column;
align-items: center;
}
.menu {
flex-direction: column;
}
.menu-item {
margin: 0px 10px 10px 0px;
}
}
@media (max-width: 480px) {
.btn-outline-primary {
width: 100%;
text-align: center;
}
.buttons {
flex-direction: column;
width: 100%;
}
.btn-primary {
width: 100%;
text-align: center;
}
}
/*
FOOTER
*/
select {
background: #ebebeb;
border: white;
padding: 8px 20px;
font-size: 16px;
font-family: inherit;
}
select option {
font-family: inherit;
width: 290px;
}
.footer {
width: 100%;
background-color: var(--main);
bottom: 0;
color: white;
display: flex;
position: fixed;
justify-content: space-between;
align-items: center;
}
/***********************************
PAGINATION
***********************************/
.pagination {
box-shadow: 0 0 5px 0 var(--box-shadow);
margin: 10px auto;
padding: 8px;
display: flex;
justify-content: space-between;
align-items: center;
max-width: 400px;
gap: 10px;
position: relative;
}
.pagination .back,
.pagination .after {
color: var(--second);
font-size: 26px;
cursor: pointer;
}
.pagination .numbers {
display: flex;
align-items: center;
gap: 5px;
}
.pagination .number {
color: var(--second);
font-size: 22px;
border: 0 0 5px var(--second);
padding: 8px;
border-radius: 2px;
font-weight: 600;
cursor: pointer;
margin: 8px;
}
.pagination .number.active {
color: var(--main);
font-weight: 700;
}
/************************************
Threads
*************************************/
.threads {
width: 100%;
padding: 20px;
}
.threads-box {
width: 100%;
padding: 8px;
box-shadow: 0 0 5px 0 var(--box-shadow);
display: flex;
justify-content: space-between;
margin: 0px 0px 8px 0px;
cursor: pointer;
align-items: center;
}
.threads-box:hover {
background-color: var(--box-shadow);
}
.thread-box-title {
padding: 10px;
font-size: 18px;
font-weight: 700;
color: var(--anti);
}
.thread-box-title>span {
color: var(--important);
}
@media (max-width: 480px) {
.threads-box {
flex-direction: column;
}
}
/*****
LOGIN / REGISTER
******/
form.login {
display: flex;
align-items: center;
flex-direction: column;
max-width: 500px;
margin: 0 auto;
padding: 8px;
}
/********
MESSAGES
********/
.message .date {
color: var(--second);
}
.message {
max-width: 800px;
box-shadow: 0 0 5px 0 var(--box-shadow);
margin: 10px auto;
padding: 20px;
display: flex;
gap: 10px;
position: relative;
}
.message .left {
text-align: center;
border-right: 2px solid var(--borders);
}
.message .left img {
width: 100px;
height: 100px;
border-radius: 50%;
margin-right: 5px;
}
.message .left .username a {
color: var(--t-username);
}
.message .content {
width: 70%;
color: var(--anti);
}
@media(max-width:980px) {
.message {
margin: 10px 20px;
max-width: 100%;
flex-direction: column;
position: relative;
}
.message .left {
padding: 40px;
border: none;
border-bottom: 2px solid var(--borders);
}
.message .left img {
width: 50px;
height: 50px;
border-radius: 50%;
margin-right: 5px;
position: absolute;
left: 20px;
top: 20px;
}
.message .left .username {
position: absolute;
top: 20px;
left: 80px;
}
.message .date:nth-of-type(3) {
position: absolute;
right: 20px;
top: 20px;
}
.message .date:nth-of-type(2) {
position: absolute;
right: 20px;
top: 40px;
}
.message .content {
width: 50%;
}
}
/************************************
SEARCH
***************************************/
.search form {
display: flex;
align-items: center;
flex-direction: column;
max-width: 500px;
margin: 20px auto;
width: 100%;
padding: 10px;
box-shadow: 0 0 5px 0 #b0b0b0;
}
/****************************************
USERS
*****************************************/
.users {
width: 100%;
padding: 20px;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
gap: 10px;
}
.user-box {
width: 100%;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 0 5px 0 var(--box-shadow);
max-width: 500px;
}
.user-box-title {
padding: 10px;
margin: 8px;
font-weight: 500;
}
.user-box-title>a {
color: var(--anti);
}
.user-box-title>span {
color: var(--important);
}
.user-box-img {
width: 80px;
height: 80px;
margin: auto;
}
@media (max-width: 992px) {
.users {
display: block;
}
.user-box {
margin-bottom: 10px;
}
}
/************************************
THREAD
*************************************/
.title {
color: var(--input-clr);
font-weight: 700;
font-size: 36px;
}
.reactions {
position: absolute;
right: 20px;
bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.reactions div {
display: flex;
align-items: center;
gap: 5px;
padding: 4px;
color: var(--second);
cursor: pointer;
transition: color 0.3s ease;
}
.reactions div:hover {
color: var(--anti);
}
.reactions div i {
font-size: 22px;
}
.dots {
position: absolute;
right: 20px;
font-size: 22px;
top: 10px;
color: var(--second);
cursor: pointer;
}
.dots-menu {
position: absolute;
top: 50px;
right: 0;
background-color: var(--second);
width: 100px;
text-align: center;
display: none;
}
.active {
display: block;
}
.no-display {
display: none;
}
.dots-menu a {
display: block;
margin: 8px;
cursor: pointer;
}
.dots-menu a:hover:nth-child(1) {
color: var(--important);
}
.dots-menu a:hover:nth-child(2) {
color: var(--main);
}
/* Media Query */
@media(max-width:980px) {
.dots {
position: absolute;
right: auto;
top: 70px;
left: 40px;
}
.dots-menu {
position: absolute;
left: 70px;
top: 60px;
width: 120px;
}
.active {
display: flex;
}
}
/******************************
USER
******************************/
.usercontent {
display: flex;
flex-direction: column;
box-shadow: 0 0 5px 0 var(--box-shadow);
max-width: 900px;
margin: 0 auto;
padding: 10px;
color: var(--anti);
}
.userbox {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0 auto;
max-width: 800px;
width: 100%;
}
.userbox-title {
font-weight: 400;
color: var(--anti);
}
.userbox-value {
font-weight: 300;
background-color: var(--main);
color: white;
font-size: 14px;
padding: 4px;
border-radius: 5px;
min-width: 50px;
text-align: center;
}

View file

@ -5,5 +5,5 @@
<meta name="description" content="<%= dataset.description %>">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="stylesheet" href="/themes/default_black/main.css" />
<link rel="stylesheet" href="/themes/common/main.css" />
<link rel="stylesheet" href="/css/common.css" />
</head>

View file

@ -5,5 +5,5 @@
<meta name="description" content="<%= dataset.description %>">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="stylesheet" href="/themes/default_white/main.css" />
<link rel="stylesheet" href="/themes/common/main.css" />
<link rel="stylesheet" href="/css/common.css" />
</head>

View file

@ -80,8 +80,11 @@ app.post("/:id/ban", async (req, res) => {
});
const storage = multer.diskStorage({
destination:'./public/images/avatars',
destination: function (_req, _file, cb) {
cb(null, './public/images/avatars')
},
filename: function (req, _file, cb) {
console.log(_file)
cb(null, req.member.id + ".jpg")
}
})

View file

@ -4,13 +4,8 @@ const { Router } = require("express");
const app = Router();
app.get("/", async (req, res) => {
const page = Number(req.query.page) || 0;
const categories = await CategoryModel.find({}).limit(10).skip(page * 10).sort({ time: -1 });
res.reply("categories", {
categories, page,
pages: Math.ceil(await CategoryModel.count({}) / 10)
});
const categories = await CategoryModel.find({});
res.reply("categories", { categories });
});
app.get("/create",(req,res)=>res.reply("create_category"));

View file

@ -12,10 +12,8 @@ app.post("/", async (req, res) => {
if (!name || !password) return res.error(400, "You forgot entering some values")
const member = await UserModel.findOne({
$or: [{ name }, { email: name }]
}, "+password");
if (!member || member.deleted) return res.error(401, 'Incorrect username or email!');
const member = await UserModel.findOne({ name }, "+password");
if (!member || member.deleted) return res.error(401, 'Incorrect username!');
if (!await bcrypt.compare(password, member.password)) return res.error(401, 'Incorrect password!');
req.session.userID = member.id;

View file

@ -4,7 +4,7 @@
<%- include("extra/meta", {title: "Avatar Upload Panel!" }) %>
<body style="text-align: center;">
<link rel="stylesheet" href="/libs/cropper/cropper.css">
<link rel="stylesheet" href="/css/cropper.css">
<style>
.container {
margin: 20px auto;
@ -25,7 +25,7 @@
box-shadow: 0 0 0 1px #39f;
}
</style>
<script src="/libs/cropper/cropper.js"></script>
<script src="/js/cropper.js"></script>
<%- include("extra/navbar") %>

View file

@ -5,6 +5,9 @@
<body>
<link href='https://unpkg.com/boxicons@2.1.2/css/boxicons.min.css' rel='stylesheet'>
<link rel="stylesheet" href="/css/threads.css" />
<link rel="stylesheet" href="/css/pages.css" />
<%- include("extra/navbar") %>
<div class="threads">
<% categories.forEach(category=>{ %>
@ -30,19 +33,19 @@
<div class="pagination">
<div class="back">
<% if (page > 0){ %>
<a href="/categories?page=<%= page-1 %>" class='bx bxs-chevron-left'></a>
<a href="/threads?page=<%= page-1 %>" class='bx bxs-chevron-left'></a>
<% } %>
</div>
<div class="numbers">
<% for(let i=0; i < pages; i++){ %>
<a class="number <%= i==page?'active':'' %>" href="/categories?page=<%= i %>"><%= i+1 %></a>
<a class="number <%= i==page?'active':'' %>" href="/threads?page=<%= i %>"><%= i+1 %></a>
<% } %>
</div>
<div class="after">
<% if (pages-1 > page) { %>
<a href="/categories?page=<%= page +1 %>" class='bx bxs-chevron-right'></a>
<a href="/threads?page=<%= page +1 %>" class='bx bxs-chevron-right'></a>
<% } %>
</div>

View file

@ -3,25 +3,20 @@
<%- include("extra/meta", {title: "Create Category!" }) %>
<body>
<%- include("extra/navbar") %>
<link rel="stylesheet" href="/libs/simplemde/simplemde.min.css">
<script src="/libs/simplemde/simplemde.min.js"></script>
<link rel="stylesheet" href="/css/create_thread.css" />
<form class="post">
<%- include("extra/navbar") %>
<form>
<h2 class="title" style="align-self: baseline;">Name:</h2>
<input name="name" class="input" required ></input>
<h2 class="title" style="align-self: baseline;">Description:</h2>
<div style="width: 100%;">
<textarea id="textarea"></textarea>
</div>
<textarea rows="4" cols="50" name="desp" class="input" required></textarea>
<button class="btn-primary" style="width:100%" type="submit">Create Category!</button>
</form>
<script src="/js/editor.js"></script>
<script type="module">
const simplemde = editor("category-create");
import request from "../../js/request.js";
document.addEventListener("submit", async e => {
@ -30,11 +25,9 @@
const response = await request("/api/categories/", "POST", {
name: data.get("name"),
desp: simplemde.value()
desp: data.get("desp")
});
simplemde.clearAutosavedValue();
if (response)
window.location.href = "/categories/" + response.id;

View file

@ -4,12 +4,12 @@
<%- include("extra/meta", {title: "Create thread!" }) %>
<body >
<link rel="stylesheet" href="/css/create_thread.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">
<script src="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script>
<%- include("extra/navbar") %>
<link rel="stylesheet" href="/libs/simplemde/simplemde.min.css">
<script src="/libs/simplemde/simplemde.min.js"></script>
<form class="post">
<form>
<h2 class="title" style="align-self: baseline;">Title:</h2>
<input name="title" class="input" required></input>
<h2 class="title" style="align-self: baseline;">Content:</h2>
@ -18,7 +18,7 @@
</div>
<h2 class="title" style="align-self: baseline;">Category:</h2>
<select name="category" class="input">
<select name="category">
<% for (const category of categories) { %>
<option value="<%= category.id %>"><%= category.name %></option>
<% } %>
@ -26,11 +26,21 @@
<button class="btn-primary" style="width:100%" type="submit">Create Thread!</button>
</form>
<script src="/js/editor.js"></script>
<script type="module">
const simplemde = editor("thread-create");
const textarea = document.getElementById("textarea");
const simplemde = new SimpleMDE({
autosave: {
enabled: true,
uniqueId: "thread-create",
delay: 1000,
},// width: 100%;
element: textarea,
spellChecker: false
});
import request from "../../js/request.js";
@ -45,7 +55,6 @@
category: data.get("category")
});
simplemde.clearAutosavedValue();
if (response)
window.location.href = "/threads/" + response.id;

View file

@ -6,9 +6,6 @@
<body>
<%- include("extra/navbar") %>
<link rel="stylesheet" href="/libs/simplemde/simplemde.min.css">
<script src="/libs/simplemde/simplemde.min.js"></script>
<h1 class="title" style="text-align:center;">
Edit <a href="/users/<%= member.id %>"><%= member.name %></a>
</h1>
@ -16,7 +13,7 @@
<form id="form" style="box-shadow:none">
<input type="text" name="name" placeholder="<%=member.name%>" class="input">
<textarea id="textarea" class="input" name="about" rows="4" cols="60" name="content" placeholder="<%=member.about%>"></textarea>
<textarea class="input" name="about" rows="4" cols="60" name="content" placeholder="<%=member.about%>"></textarea>
<% if (user?.admin){ %>
Is Admin? <input id='admin' type='checkbox' value='true' name='admin' <%=member.admin ? "checked": ""%>>
<input id='adminHidden' type='hidden' value='false' name='admin'>
@ -24,25 +21,18 @@
<button class="btn-primary" style="width:100%;">Update User!</button>
</form>
<script src="/js/editor.js"></script>
<script type="module">
import request from "/js/request.js";
const simplemde = editor("user-edit-<%=member.id%>");
document.getElementById("form").addEventListener("submit", async e => {
e.preventDefault();
document.getElementById('adminHidden').disabled = document.getElementById("admin").checked;
const formdata=new FormData(e.target)
const res = await request("/api/users/<%=member.id%>", "PATCH", {
name: formdata.get("name"),
about: simplemde.value(),
admin: formdata.get("admin")
});
simplemde.clearAutosavedValue();
const object = {};
new FormData(e.target).forEach((value, key) => object[key] = value);
const res = await request("/api/users/<%=member.id%>", "PATCH", object);
if (res) alert(`User is updated!`);
location.reload();
});

View file

@ -9,7 +9,7 @@
<%- include("extra/navbar") %>
<div class="usercontent">
<div class="content">
<% if (user) { %>
<h2 style="color: var(--main);">
<div class="box-username">Welcome, <%= user.name %>
@ -28,24 +28,24 @@
<h2 style="color: var(--second);">Statistics:</h2>
<div class="userbox">
<h2 class="userbox-title">Message count:</h2>
<h2 class="userbox-value"><%= messages %></h2>
<div class="box">
<h2 class="box-title">Message count:</h2>
<h2 class="box-value"><%= messages %></h2>
</div>
<div class="userbox">
<h2 class="userbox-title">User count: </h2>
<h2 class="userbox-value"><%= users %> </h2>
<div class="box">
<h2 class="box-title">User count: </h2>
<h2 class="box-value"><%= users %> </h2>
</div>
<div class="userbox">
<h2 class="userbox-title">Thread count:</h2>
<h2 class="userbox-value"><%= threads %></h2>
<div class="box">
<h2 class="box-title">Thread count:</h2>
<h2 class="box-value"><%= threads %></h2>
</div>
<div class="userbox">
<h2 class="userbox-title">Memory usage:</h2>
<h2 class="userbox-value"><%= mem.toFixed(2); %> MB</h2>
<div class="box">
<h2 class="box-title">Memory usage:</h2>
<h2 class="box-value"><%= mem.toFixed(2); %> MB</h2>
</div>
</div>

View file

@ -4,21 +4,20 @@
<%- include("extra/meta", {title: "Log in!" }) %>
<body style="text-align: center;">
<link rel="stylesheet" href="/css/login.css" />
<%- include("extra/navbar") %>
<% if(discord) { %>
<a href="<%=discord%>" class="btn-outline-primary">Login with discord</a>
<% } %>
<h1 class="title">Login</h1>
<form class="login" action="/login?redirect=<%= redirect !== "/register" ? redirect : "/" %>" method="post">
<form action="/login?redirect=<%= redirect !== "/register" ? redirect : "/" %>" method="post">
<input type="text" name="name" placeholder="Email/Username" class="input" required>
<input type="text" name="name" placeholder="Username" class="input" required>
<input type="password" name="password" placeholder="Password" class="input" required>
<input type="submit" style="width:100%" class="btn-primary" value="Login">
</form>
<% if(discord) { %>
<a href="<%=discord%>" class="btn-outline-primary">Auth with discord</a>
<% } %>
<a href="/register" class="btn-outline-primary">Register</a>
<%- include("extra/footer") %>

View file

@ -6,6 +6,7 @@
<body style="text-align: center;">
<%- include("extra/navbar") %>
<link rel="stylesheet" href="/css/messages.css" />
<div id="messages">

View file

@ -5,24 +5,22 @@
<body style="text-align: center;">
<link rel="stylesheet" href="/css/login.css" />
<%- include("extra/navbar") %>
<% if(discord) { %>
<a href="<%=discord%>" class="btn-outline-primary">Login with discord</a>
<% } %>
<h1 class="title">Register</h1>
<form class="login" action="/register" method="post">
<form action="/register" method="post">
<input type="email" name="email" placeholder="Email" class="input" required>
<input type="text" name="name" placeholder="Username" class="input" required>
<input type="password" name="password" placeholder="Password" class="input" required>
<textarea class="input" name="about" rows="4" placeholder="About you... You can use markdown"></textarea>
<input type="submit" class="btn-primary" style="width:100%;" value="Register">
</form>
<% if(discord) { %>
<a href="<%=discord%>" class="btn-outline-primary">Auth with discord</a>
<% } %>
<a href="/login" class="btn-outline-primary">Login</a>
<%- include("extra/footer") %>

View file

@ -6,21 +6,24 @@
<body style="text-align: center;">
<%- include("extra/navbar") %>
<link rel="stylesheet" href="/css/search.css" />
<h1 class="title">Search</h1>
<div class="search">
<div id="search">
<form action="/search/users" method="GET">
<input type="text" class="input" name="q" placeholder="Search for users" />
<input type="submit" class="btn-primary" value="Search" />
</form>
</div>
<div id="search">
<form action="/search/messages" method="GET">
<input type="text" class="input" name="q" placeholder="Search for messages" />
<input type="text" class="input" name="authorID" placeholder="(Not Required) Author id" />
<input type="submit" value="Search" class="btn-primary" />
</form>
</div>
<div id="search">
<form action="/search/threads" method="GET">
<input type="text" class="input" name="q" placeholder="Search for threads" />
<input type="text" class="input" name="authorID" placeholder="(Not Required) Author id" />

View file

@ -6,24 +6,22 @@
<body style="text-align: center;">
<%- include("extra/navbar") %>
<link rel="stylesheet" href="/css/setup.css">
<h1 style="color: var(--main);">Setup</h1>
<h2 style="color: var(--second);">There is default settings for akf-forum, you not need to edit them, but you can! And, the first registered user will be admin.</h2>
<form class="search" method="POST">
<form method="POST">
Forum name:
<input class="input" type="text" name="forum_name" value="akf" required>
<input type="text" name="forum_name" value="akf" required>
Forum description:
<input class="input" type="text" name="description" value="Akf-forum!" required>
<input type="text" name="description" value="Akf-forum!" required>
Default state for new threads, change with "APPROVAL" for approval system:
<input class="input" type="text" name="default_thread_state" value="OPEN" required>
Default state for new users, change with "APPROVAL" for approval system:
<input class="input" type="text" name="default_thread_state" value="ACTIVE" required>
<input type="text" name="default_thread_state" value="OPEN" required>
Domain of the forum, defaulty setted:
<input class="input" type="text" name="host" id="domain" value="Akf-forum!" required>
<input type="text" name="host" id="domain" value="Akf-forum!" required>
<hr>
(Optional) Discord app ID for Discord login:
<input class="input" type="text" name="discord_auth">
<input type="text" name="discord_auth">
<input type="submit" class="btn-primary" value="Setup">
</form>

View file

@ -1,15 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/2.1.0/showdown.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">
<script src="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script>
<link href='https://unpkg.com/boxicons@2.1.2/css/boxicons.min.css' rel='stylesheet'>
<%- include("extra/meta", {title: thread.title }) %>
<body>
<%- include("extra/navbar") %>
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/2.1.0/showdown.min.js"></script>
<link href='https://unpkg.com/boxicons@2.1.2/css/boxicons.min.css' rel='stylesheet'>
<link rel="stylesheet" href="/libs/simplemde/simplemde.min.css">
<script src="/libs/simplemde/simplemde.min.js"></script>
<link rel="stylesheet" href="/css/thread.css" />
<link rel="stylesheet" href="/css/pages.css" />
<div style="text-align:center;padding:8px">
<a href="/categories/<%= thread.categoryID %>" class="title" id="title"><%= thread.title %></a>
@ -109,11 +115,17 @@
</form>
</div>
<script src="/js/editor.js"></script>
<script type="module">
const simplemde = editor("thread-<%= thread.id %>");
const textarea = document.getElementById("textarea");
const simplemde = new SimpleMDE({
autosave: {
enabled: true,
uniqueId: "thread-<%= thread.id %>",
delay: 1000,
},
element: textarea,
spellChecker: false
});
import request from "../../js/request.js";

View file

@ -5,6 +5,9 @@
<body style="color: var(--anti); text-align: center;">
<link href='https://unpkg.com/boxicons@2.1.2/css/boxicons.min.css' rel='stylesheet'>
<link rel="stylesheet" href="/css/threads.css" />
<link rel="stylesheet" href="/css/pages.css" />
<%- include("extra/navbar") %>
<h1><%= title || "Threads" %></h1>
<h2><%= desp %></h2>

View file

@ -5,25 +5,26 @@
<body>
<%- include("extra/navbar") %>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css" integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/2.1.0/showdown.min.js"></script>
<div class="usercontent">
<link rel="stylesheet" href="/css/user.css" />
<%- include("extra/navbar") %>
<div class="content">
<%- include(dataset.getFile(dataset.theme.codename +"/extra/usermenu")) %>
<div class="userbox" style="justify-content:center;">
<div class="box" style="justify-content:center;">
<img style="width:150px;height:150px;border-radius:50%;" src="<%=member.avatar %>">
</div>
<% if (member.admin) { %>
<h2 class="userbox-value" style="align-self: center;">Admin</h2>
<h2 class="box-value" style="align-self: center;">Admin</h2>
<% } %>
<% if (member.about?.length) { %>
<div class="userbox-value" id="about" style="
<div class="box-value" id="about" style="
margin: 10px auto;
box-shadow: 0 0 5px 0 var(--second);
padding: 10px;
@ -45,29 +46,29 @@ color: var(--anti);
<div class="userbox">
<h2 class="userbox-title">Name:</h2>
<h2 class="userbox-value"><%= member.name %></h2>
<div class="box">
<h2 class="box-title">Name:</h2>
<h2 class="box-value"><%= member.name %></h2>
</div>
<div class="userbox">
<h2 class="userbox-title">Created at:</h2>
<h2 class="userbox-value"><%= new Date(member.time).toLocaleString() %></h2>
<div class="box">
<h2 class="box-title">Created at:</h2>
<h2 class="box-value"><%= new Date(member.time).toLocaleString() %></h2>
</div>
<% if(!member.hideLastSeen || user?.admin) {%>
<div class="userbox">
<h2 class="userbox-title">Last seen at:</h2>
<h2 class="userbox-value"><%= new Date(member.lastSeen).toLocaleString() %></h2>
<div class="box">
<h2 class="box-title">Last seen at:</h2>
<h2 class="box-value"><%= new Date(member.lastSeen).toLocaleString() %></h2>
</div>
<% } %>
<div class="userbox">
<h2 class="userbox-title">Message:</h2>
<a class="userbox-value" href="/search/messages?authorID=<%= member.id %>">
<div class="box">
<h2 class="box-title">Message:</h2>
<a class="box-value" href="/search/messages?authorID=<%= member.id %>">
<%= counts.message %>
</a>
</div>
<div class="userbox">
<h2 class="userbox-title">Thread:</h2>
<a class="userbox-value" href="/search/threads?authorID=<%= member.id %>">
<div class="box">
<h2 class="box-title">Thread:</h2>
<a class="box-value" href="/search/threads?authorID=<%= member.id %>">
<%= counts.thread %>
</a>
</div>

View file

@ -6,6 +6,8 @@
<body>
<link href='https://unpkg.com/boxicons@2.1.2/css/boxicons.min.css' rel='stylesheet'>
<link rel="stylesheet" href="/css/users.css" />
<link rel="stylesheet" href="/css/pages.css" />
<%- include("extra/navbar") %>
<div class="users">