Compare commits

...

4 commits

Author SHA1 Message Date
667c0222e9 5.2.0 2023-05-24 15:43:45 +03:00
30c701c09e login with email 2023-05-24 15:43:40 +03:00
10b021c16f 5.1.1 2023-05-24 15:40:15 +03:00
8c78ecaed1 page support for categories, and one css file 2023-05-24 15:40:09 +03:00
44 changed files with 1266 additions and 933 deletions

View file

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

View file

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

4
package-lock.json generated
View file

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

View file

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

View file

@ -1,215 +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);
}
@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

@ -1,27 +0,0 @@
.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%;
}

View file

@ -1,26 +0,0 @@
.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);
}

View file

@ -1,34 +0,0 @@
.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);
}

View file

@ -1,75 +0,0 @@
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%;
}
}

View file

@ -1,41 +0,0 @@
.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;
}

View file

@ -1,27 +0,0 @@
.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);
}

View file

@ -1,26 +0,0 @@
.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);
}

View file

@ -1,179 +0,0 @@
.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%;
}
}

View file

@ -1,38 +0,0 @@
.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;
}
}

View file

@ -1,39 +0,0 @@
.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;
}

View file

@ -1,47 +0,0 @@
.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;
}
}

15
public/js/editor.js Normal file
View file

@ -0,0 +1,15 @@
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

15
public/libs/simplemde/simplemde.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

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

View file

@ -185,6 +185,26 @@ div.avatar {
color: var(--main); 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) { @media (max-width: 992px) {
.header { .header {
flex-direction: column; flex-direction: column;
@ -271,3 +291,405 @@ a {
margin-top: 25px; margin-top: 25px;
margin-bottom: 125px; 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

@ -0,0 +1,643 @@
@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 %>"> <meta name="description" content="<%= dataset.description %>">
<link rel="icon" type="image/x-icon" href="/favicon.ico"> <link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="stylesheet" href="/themes/default_black/main.css" /> <link rel="stylesheet" href="/themes/default_black/main.css" />
<link rel="stylesheet" href="/css/common.css" /> <link rel="stylesheet" href="/themes/common/main.css" />
</head> </head>

View file

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

View file

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

View file

@ -1,20 +1,25 @@
const { CategoryModel,ThreadModel } = require("../models"); const { CategoryModel, ThreadModel } = require("../models");
const { Router } = require("express"); const { Router } = require("express");
const app = Router(); const app = Router();
app.get("/", async (req, res) => { app.get("/", async (req, res) => {
const categories = await CategoryModel.find({}); const page = Number(req.query.page) || 0;
res.reply("categories", { categories });
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)
});
}); });
app.get("/create",(req,res)=>res.reply("create_category")); app.get("/create", (req, res) => res.reply("create_category"));
app.get("/:id", async (req, res) => { app.get("/:id", async (req, res) => {
const category = await CategoryModel.findOne({ id: req.params.id }); const category = await CategoryModel.findOne({ id: req.params.id });
if (!category) return res.error(404, "Category not found."); if (!category) return res.error(404, "Category not found.");
const page = Number(req.query.page) || 0; const page = Number(req.query.page) || 0;
const query = { categoryID: category.id }; const query = { categoryID: category.id };
if (!req.user?.admin) query.deleted= false; if (!req.user?.admin) query.deleted = false;
let threads = await ThreadModel.find(query).limit(10).skip(page * 10).sort({ time: -1 }); let threads = await ThreadModel.find(query).limit(10).skip(page * 10).sort({ time: -1 });
threads = await Promise.all(threads.map(thread => thread.get_author())); threads = await Promise.all(threads.map(thread => thread.get_author()));

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,22 +6,24 @@
<body style="text-align: center;"> <body style="text-align: center;">
<%- include("extra/navbar") %> <%- include("extra/navbar") %>
<link rel="stylesheet" href="/css/setup.css">
<h1 style="color: var(--main);">Setup</h1> <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> <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 method="POST"> <form class="search" method="POST">
Forum name: Forum name:
<input type="text" name="forum_name" value="akf" required> <input class="input" type="text" name="forum_name" value="akf" required>
Forum description: Forum description:
<input type="text" name="description" value="Akf-forum!" required> <input class="input" type="text" name="description" value="Akf-forum!" required>
Default state for new threads, change with "APPROVAL" for approval system: Default state for new threads, change with "APPROVAL" for approval system:
<input type="text" name="default_thread_state" value="OPEN" required> <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>
Domain of the forum, defaulty setted: Domain of the forum, defaulty setted:
<input type="text" name="host" id="domain" value="Akf-forum!" required> <input class="input" type="text" name="host" id="domain" value="Akf-forum!" required>
<hr> <hr>
(Optional) Discord app ID for Discord login: (Optional) Discord app ID for Discord login:
<input type="text" name="discord_auth"> <input class="input" type="text" name="discord_auth">
<input type="submit" class="btn-primary" value="Setup"> <input type="submit" class="btn-primary" value="Setup">
</form> </form>

View file

@ -1,21 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <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 }) %> <%- include("extra/meta", {title: thread.title }) %>
<body> <body>
<%- include("extra/navbar") %> <%- 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="/css/thread.css" /> <link rel="stylesheet" href="/libs/simplemde/simplemde.min.css">
<link rel="stylesheet" href="/css/pages.css" /> <script src="/libs/simplemde/simplemde.min.js"></script>
<div style="text-align:center;padding:8px"> <div style="text-align:center;padding:8px">
<a href="/categories/<%= thread.categoryID %>" class="title" id="title"><%= thread.title %></a> <a href="/categories/<%= thread.categoryID %>" class="title" id="title"><%= thread.title %></a>
@ -115,17 +109,11 @@
</form> </form>
</div> </div>
<script src="/js/editor.js"></script>
<script type="module"> <script type="module">
const textarea = document.getElementById("textarea"); const simplemde = editor("thread-<%= thread.id %>");
const simplemde = new SimpleMDE({
autosave: {
enabled: true,
uniqueId: "thread-<%= thread.id %>",
delay: 1000,
},
element: textarea,
spellChecker: false
});
import request from "../../js/request.js"; import request from "../../js/request.js";
@ -143,11 +131,11 @@
if (res) location.href = `/threads/<%= thread.id %>?page=${tp-1}`; if (res) location.href = `/threads/<%= thread.id %>?page=${tp-1}`;
}); });
</script> </script>
<style> <style>
.fa { .fa {
color: var(--main); color: var(--main);
} }
</style> </style>
<% }%> <% }%>

View file

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

View file

@ -5,26 +5,25 @@
<body> <body>
<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>
<link rel="stylesheet" href="/css/user.css" />
<%- include("extra/navbar") %> <%- include("extra/navbar") %>
<div class="content"> <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">
<%- include(dataset.getFile(dataset.theme.codename +"/extra/usermenu")) %> <%- include(dataset.getFile(dataset.theme.codename +"/extra/usermenu")) %>
<div class="box" style="justify-content:center;"> <div class="userbox" style="justify-content:center;">
<img style="width:150px;height:150px;border-radius:50%;" src="<%=member.avatar %>"> <img style="width:150px;height:150px;border-radius:50%;" src="<%=member.avatar %>">
</div> </div>
<% if (member.admin) { %> <% if (member.admin) { %>
<h2 class="box-value" style="align-self: center;">Admin</h2> <h2 class="userbox-value" style="align-self: center;">Admin</h2>
<% } %> <% } %>
<% if (member.about?.length) { %> <% if (member.about?.length) { %>
<div class="box-value" id="about" style=" <div class="userbox-value" id="about" style="
margin: 10px auto; margin: 10px auto;
box-shadow: 0 0 5px 0 var(--second); box-shadow: 0 0 5px 0 var(--second);
padding: 10px; padding: 10px;
@ -46,29 +45,29 @@ color: var(--anti);
<div class="box"> <div class="userbox">
<h2 class="box-title">Name:</h2> <h2 class="userbox-title">Name:</h2>
<h2 class="box-value"><%= member.name %></h2> <h2 class="userbox-value"><%= member.name %></h2>
</div> </div>
<div class="box"> <div class="userbox">
<h2 class="box-title">Created at:</h2> <h2 class="userbox-title">Created at:</h2>
<h2 class="box-value"><%= new Date(member.time).toLocaleString() %></h2> <h2 class="userbox-value"><%= new Date(member.time).toLocaleString() %></h2>
</div> </div>
<% if(!member.hideLastSeen || user?.admin) {%> <% if(!member.hideLastSeen || user?.admin) {%>
<div class="box"> <div class="userbox">
<h2 class="box-title">Last seen at:</h2> <h2 class="userbox-title">Last seen at:</h2>
<h2 class="box-value"><%= new Date(member.lastSeen).toLocaleString() %></h2> <h2 class="userbox-value"><%= new Date(member.lastSeen).toLocaleString() %></h2>
</div> </div>
<% } %> <% } %>
<div class="box"> <div class="userbox">
<h2 class="box-title">Message:</h2> <h2 class="userbox-title">Message:</h2>
<a class="box-value" href="/search/messages?authorID=<%= member.id %>"> <a class="userbox-value" href="/search/messages?authorID=<%= member.id %>">
<%= counts.message %> <%= counts.message %>
</a> </a>
</div> </div>
<div class="box"> <div class="userbox">
<h2 class="box-title">Thread:</h2> <h2 class="userbox-title">Thread:</h2>
<a class="box-value" href="/search/threads?authorID=<%= member.id %>"> <a class="userbox-value" href="/search/threads?authorID=<%= member.id %>">
<%= counts.thread %> <%= counts.thread %>
</a> </a>
</div> </div>

View file

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