// controllers/front/home.js

import config from '../../config.js'
import _Home from '../../views/front/home.jsx'
import postdb from '../../models/postdb.ts'

class Home{
  async getItem(req, res){
    this.config = await config()
    this.config.pageTitle = 'ទំព័រ​ដើម'
    this.config.route = '/'

    let {items} = await postdb.getItem(req, 10)
    this.config.posts = items

    const html = await _Home(this.config)
    res.send(html)
  }
}

export default new Home()

 

// models/postdb.js

interface PostSchema {
    _id: ObjectId;
    id: string; 
    title: string;
    content: string;
    categories: string[];
    thumb: string;
    postdate: string;
    video: string;
    userid: string;
}

class Postdb{
    async count(req, query={}){
        const posts = req.mydb.collection<PostSchema>("posts")
        return await posts.countDocuments(query)
    }

    async insertPost(req){
        const id = Date.now() + Math.round(Math.random() * 1E9).toString()

        if(req.body.categories.includes(',')){
            var categories: string[] = req.body.categories.split(',')
        }else{
            var categories: string[] = [req.body.categories]
        }

        const user_id = await req.session.get('user-id')
        
        let newPost = {
            id: id, 
            title: req.body.title,
            content: req.body.content,
            categories: categories,
            thumb: req.body.thumb,
            postdate: req.body.datetime,
            video: req.body.video,
            userid: user_id,
        }
 
        const posts = req.mydb.collection<PostSchema>("posts")
        await posts.insertOne(newPost)
    }

    async getItem(req, amount, query={}){
        const posts = req.mydb.collection<PostSchema>("posts")
        let item = null

        if(req.params.id){
            item = await posts.findOne({id: req.params.id})
        }

        const items = await posts.find(query).sort({date:-1,_id:-1}).limit(amount).toArray()
        return {item:item, items:items}
    }

    async editPost(req){
        if(req.body.categories.includes(',')){
            var categories: string[] = req.body.categories.split(',')
        }else{
            var categories: string[] = [req.body.categories]
        }

        let editPost = {$set:{
            title: req.body.title,
            content: req.body.content,
            categories: categories,
            thumb: req.body.thumb,
            postdate: req.body.datetime,
            video: req.body.video,
        }}
        
        const posts = req.mydb.collection<PostSchema>("posts")
        await posts.updateOne({id: req.params.id}, editPost)
    }

    async deletePost(req){
        const posts = req.mydb.collection<PostSchema>("posts")

        if(req.params.id){
            var item = await posts.findOne({id: req.params.id})
        }

        const user_id = await req.session.get('user-id')

        const user_role = await req.session.get('user-role')
        if(user_role in {'Admin':1,'Editor':1,'Author':1}){
            if((user_role === 'Admin') || (user_id === item.userid)){
                await posts.deleteOne({id: req.params.id})
            }
        }
    }
}

export default new Postdb

 

// views/front/home.jsx

/** @jsx h */
import { h, renderSSR } from "../../deps.ts"

function HomeJsx(props){

  let content = []

  for(let post of props.config.posts){
    content.push(
      <div class="post">
        <a class="thumb" href={`/post/${post.id}`}>
          <img src={post.thumb} />
          {((post.video) && (post.video !== "[]")) &&
          <img class="play-icon" src="/images/play.png" />
      }
        </a>
        <div class="post-content">
          <a class="title" href={`/post/${post.id}`}>{post.title}</a>
          <span>{(new Date(post.postdate)).toLocaleDateString('it-IT')}</span>
          <div class="except" dangerouslySetInnerHTML={{__html: `${post.content}`}}/>
        </div>
      </div>
    )
  }

  return(
    <html>
      <head>
        <meta charset="UTF-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <title>{props.config.siteTitle} | {props.config.pageTitle}</title>
        <link href="/images/siteLogo.png" rel="icon" />
        <link href="/styles/base.css" rel="stylesheet" />
        <link href="/fonts/setup.css" rel="stylesheet" />
        <script src="/scripts/jquery.js"></script>
        <link rel="stylesheet" href="/styles/front/home.css" />
        <link rel="stylesheet" href="/styles/front/menu.css" />
      </head>
      <body>
        <section class="Home">
            <header>
              <div class="inner region">
                <div class="title"><a href="/">{props.config.siteTitle}</a></div>
                <form action="/search" method="post">
                  <select name='category'>
                    <option>ការផ្សាយ</option>
                  </select>
                  <input type="text" name="q" required placeholder="Search" />
                  <input type="submit" value="ស្វែងរក" />
                </form>
                <div class="login"><a href="/login">ចូល​ក្នុង</a> | <a href="#register">ចុះ​ឈ្មោះ</a></div>
              </div>
            </header>

            <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
            <div class="menu">
              <div class="innner region">
              <div class="topnav" id="myTopnav">
                <a href="/" class="active">Home</a>
                <a href="#news">News</a>
                <a href="#contact">Contact</a>
                <a href="#about">About</a>
                <span dangerouslySetInnerHTML={{__html: `
                    <a href="javascript:void(0);" class="icon" onclick='myFunction()'>
                      <i class="fa fa-bars"></i>
                    </a>
                `}}/>
              </div>
              </div>
            </div>
            <script dangerouslySetInnerHTML={{__html: `
              function myFunction() {
                var x = document.getElementById("myTopnav");
                if (x.className === "topnav") {
                x.className += " responsive";
                } else {
                x.className = "topnav";
                }
              }
            `}}/>

              <div class="main region">
                <div class="content">{(content)}</div>
                <div class="sidebar">Sidebar</div>
              </div>

        </section>
      </body>
    </html>
  )
}

function Home(config){
  const str = renderSSR(<HomeJsx config={config} />)
  const html = `<!DOCTYPE html>${str}`
  return html
}

export default Home

 

/* static/styles/front/home.css */

.Home header{
    background: var(--background-dark);
    color: white;
}

.Home header .inner{
    display: grid;
    grid-template-columns: 25% auto 25%;
    align-items: center;
    padding: 20px 0;
}

.Home header .inner .title{
    font: 35px/1.5 Oswald, Limonf3;
}

.Home header .inner form{
    display: grid;
    grid-template-columns: 20% auto 20%;
}

.Home header .inner form input,
.Home header .inner form select{
    font: var(--body-font);
    padding: 2px 5px;
}

.Home header .inner .login{
    text-align: right;
}

.Home .menu{
    background: var(--background);
    margin-bottom: 20px;
}

.Home .main{
    display: grid;
    grid-template-columns: 70% auto;
    grid-gap: 15px;
    margin-bottom: 30px;
}

.Home .main .content, .Home .main .sidebar{
    background: white;
    padding: 20px;
}

.Home .main .content .post{
    display: grid;
    grid-template-columns: 30% 70%;
    margin-bottom: 20px;
    background: rgb(243, 243, 243);
    color: grey;
}

.Home .main .content .post:last-child{
    margin-bottom: 0;
}

.Home .main .content .post .thumb{
    position: relative;
    padding-top: 56.25%;
}

.Home .main .content .post .thumb img{
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

.Home .main .content .post .thumb .play-icon{
    height: auto;
    width: 20%;
    top: 2px;
    left: 2px;
}

.Home .main .content .post .post-content{
    padding: 5px 15px;
    color: rgb(32, 32, 32);
}

.Home .main .content .post .post-content .title{
    font: 22px/1.5 Oswald, Limonf3;
    color: teal;
    padding-bottom: 5px;
    display: block;
    width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis
}

.Home .main .content .post .post-content .except p{
    padding-top: 5px;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    font: 14px/1.5 Vidaloka, OdorMeanChey;
}

@media only screen and (max-width: 600px){
    .Home header .inner{
        grid-template-columns: 100%;
        padding: 5px;
    }

    .Home header .inner form{
        padding: 5px 0;
    }

    .Home header .inner .title{
        text-align: center;
    }

    .Home .main, .Home .main .content .post{
        grid-template-columns: 100%;
    }
}

 

GitHub: https://github.com/Sokhavuth/khmerweb-deno

Deno Deploy: https://khmerweb-blog.deno.dev