// 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%; } }
GitHub: https://github.com/Sokhavuth/khmerweb-fresh
Deno Deploy: https://khmerweb-fresh.deno.dev