GitHub: https://github.com/Sokhavuth/deno-fresh
Deno Deploy: https://khmerweb-fresh.deno.dev
// routes/index.tsx
/** @jsx h */
import { h } from "preact";
import { Handlers, PageProps } from "$fresh/server.ts";
import VHome from '../components/front/home.jsx';
import CHome from "../controllers/front/home.js";
export const handler: Handlers = {
async GET(req, ctx) {
return await CHome.getPosts(req, ctx);
},
}
export default function Template(props: PageProps){
return (
<VHome data={props.data} />
)
}
// controllers/front/home.js
import { setting } from "setting";
import postdb from "../../models/post.ts"
class Home{
async getPosts(req, ctx){
const config = setting();
config.items = await postdb.getPosts(config.homePostAmount);
return await ctx.render({"setting": config});
}
}
export default new Home();
// models/post.ts
import { mydb } from "setting"
interface PostSchema {
_id: ObjectId;
id: string;
title: string;
content: string;
categories: string[];
thumb: string;
date: string;
videos: string;
userid: string;
}
class Post{
async count(query={}){
const posts = mydb.collection<PostSchema>("posts")
return await posts.countDocuments(query)
}
async insertPost(req, user_id: string){
const id = crypto.randomUUID()
const formData = await req.formData()
let categories: string[]
if(formData.get("categories").includes(',')){
categories = formData.get("categories").split(',')
}else{
categories = [formData.get("categories")]
}
const new_post = {
id: id,
title: formData.get("title"),
content: formData.get("content"),
categories: categories,
thumb: formData.get("thumb"),
date: formData.get("datetime"),
videos: formData.get("videos"),
userid: user_id,
}
const posts = mydb.collection<PostSchema>("posts")
await posts.insertOne(new_post)
}
async getPosts(amount: number, query={}){
const posts = mydb.collection<PostSchema>("posts")
return await posts.find(query).sort({date:-1,_id:-1}).limit(amount).toArray()
}
async getPost(post_id: string){
const posts = mydb.collection<PostSchema>("posts")
return await posts.findOne({id: post_id})
}
async updatePost(req, post_id: string){
const formData = await req.formData()
let categories: string[]
if(formData.get("categories").includes(',')){
categories = formData.get("categories").split(',')
}else{
categories = [formData.get("categories")]
}
const edited_post = {$set:{
title: formData.get("title"),
content: formData.get("content"),
categories: categories,
thumb: formData.get("thumb"),
date: formData.get("datetime"),
videos: formData.get("videos"),
}}
const posts = mydb.collection<PostSchema>("posts")
await posts.updateOne({id: post_id}, edited_post)
}
async deletePost(post_id: string){
const posts = mydb.collection<PostSchema>("posts")
await posts.deleteOne({id: post_id})
}
async paginatePosts(amount: number, page: number){
const posts = mydb.collection<PostSchema>("posts")
return await posts.find().skip(amount*page).sort({date:-1,_id:-1}).limit(amount).toArray();
}
}
export default new Post()
// components/front/home.jsx
/** @jsx h */
import { h } from "preact";
import Base from "../base.jsx";
function HomeJsx(props){
const items = props.data.setting.items;
const listItems = items.map((item) =>
<li>
<a class="thumb" href={`/post/${item.id}`}>
<img src={item.thumb} />
{((item.videos !== "" )&&(item.videos !== "[]")) &&
<img class="play-icon" src={`/images/play.png`} />
}
</a>
<div class="title">
<a href={`/post/${item.id}`}>{item.title}</a>
<div class="date">{(new Date(item.date)).toLocaleDateString('it-IT')}</div>
<div class="text" dangerouslySetInnerHTML={{ __html: `${ item.content }` }} />
</div>
</li>
)
return(
<section class="Home">
<link href="/styles/front/home.css" rel="stylesheet" />
<script src="/scripts/menu.js"></script>
<header>
<div class="inner region">
<div class="title"><a href="/">{ props.data.setting.site_title }</a></div>
<form action="search" method="post">
<select class="category" name="frontSearch">
<option>Posts</option>
<option>Books</option>
</select>
<input type="text" name="q" required placeholder="Search" />
<input type="submit" value="Submit" />
</form>
<div class="login">
<a href="/login">Login</a> | <a href="#">Register</a>
</div>
</div>
</header>
<div class="menu">
<div class="inner region">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
<link rel="stylesheet" href="/styles/front/menu.css" />
<div class="topnav" id="myTopnav" dangerouslySetInnerHTML={{__html: `
<a href="/" class="active">Home</a>
<a href="#news">News</a>
<a href="#contact">Contact</a>
<a href="#about">About</a>
<a href="javascript:void(0);" class="icon" onclick="mobileMenu()">
<i class="fa fa-bars"></i>
</a>
`}}/>
</div>
</div>
<link rel="stylesheet" href="styles/front/main.css" />
<div class="main region">
<div class="content">
<ul> { listItems } </ul>
</div>
<div class="sidebar">Sidebar</div>
</div>
</section>
)
}
export default function Home(props){
props.data.page = HomeJsx;
return(
<Base data={props.data} />
)
}
/* static/styles/front/main.css */
.Home .main{
padding-top: 20px;
display: grid;
grid-template-columns: 70% calc(30% - 15px);
grid-gap: 15px;
padding-bottom: 30px;
}
.Home .main .content,
.Home .main .sidebar{
background: white;
padding: 20px;
}
.Home .main .content ul{
list-style-type: none;
}
.Home .main .content ul li{
display: grid;
grid-template-columns: 35% 65%;
margin-bottom: 20px;
background: rgb(243, 243, 243);
}
.Home .main .content ul li:last-child{
margin-bottom: 0;
}
.Home .main .content ul li .thumb{
position: relative;
padding-top: 56.25%
}
.Home .main .content ul li .thumb img{
position: absolute;
top: 0%;
left: 0;
width: 100%;
height: 100%;
}
.Home .main .content ul li .thumb .play-icon{
width: 20%;
height: auto;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.Home .main .content ul li .title{
padding: 5px 10px;
}
.Home .main .content ul li .title a{
font: 22px/1.5 Oswald, Limonf3;
padding-bottom: 5px;
display: block;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis
}
.Home .main .content ul li .title .text{
padding-top: 10px;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
@media only screen and (max-width: 600px){
.Home .main{
grid-template-columns: 100%;
}
.Home .main .content ul li{
grid-template-columns: 100%;
}
}
Top comments (0)