#routes/admin/category.py
from bottle import Bottle,redirect
from controllers.login import checkLogged

app = Bottle()

@app.route('/')
def getCategory():
    if checkLogged.call():
        from controllers.admin.categories import read
        return read.call()
    else:
        redirect('/login')

@app.route('/',method='post')
def postCategory():
    if checkLogged.call():
        from controllers.admin.categories import create
        return create.call()
    else:
        redirect('/login')

 

#controllers/admin/categories/read.py
import config
from copy import deepcopy
from bottle import template
from models.categories import read

def call():
    kdict = deepcopy(config.kdict)
    kdict['pageTitle'] = 'ទំព័រ​ជំពូក'
    kdict['route'] = '/admin/category'
    kdict['type'] = 'category'

    kdict['items'] = read.call(kdict['maxPosts'])

    return template('base',data=kdict)

 

#models/categories/read.py
import config
from models import setDBconnection as con

def call(amount):
    categories_ref = con.db.collection("categories")
    query = categories_ref.order_by("date",direction=con.firestore.Query.DESCENDING).limit(amount)

    results = query.get()
    categories = [category.to_dict() for category in results]
    
    return categories

 

<!--views/admin/index.tpl-->
<link href="/static/styles/admin/index.css" rel="stylesheet" />
 
<section class='Index'>
    <div class="header-wrapper">
    <header class='region'>
        <div class='logo'>{{ data['pageTitle'] }}</div>
 
        <form action='/admin/search' method='post'>
            <select name="select">
                <option>ការផ្សាយ</option>
                <option>ជំពូក</option>
                <option>សៀវភៅ</option>
                <option>អ្នក​ប្រើប្រាស់</option>
            </select>
            <input type='text' name="q" placeholder="Search" required />
            <input type="submit" value='បញ្ជូន'​ />
        </form>
 
        <div class='logout'><a href='/'>ទំព័រ​មុខ</a> | <a href='/login/logout'>ចេញ​ក្រៅ</a></div>
    </header>
    </div>

    <div class="main region">
        <div class="sidebar">
            <div class="menu">
                <a href="/admin/post"><img src="/static/images/movie.png" /></a>
                <a href="/admin/post">ការផ្សាយ</a>  

                <a href="/admin/category"><img src="/static/images/category.png" /></a>
                <a href="/admin/category">ជំពូក</a>

                <a href="/admin/upload"><img src="/static/images/upload.png" /></a>
                <a href="/admin/upload">Upload</a>

                <a href="/admin/user"><img src="/static/images/users.png" /></a>
                <a href="/admin/user">អ្នក​ប្រើប្រាស់</a>

                <a href="/admin/setting"><img src="/static/images/setting.png" /></a>
                <a href="/admin/setting">Setting</a>
            </div>
        </div>
        <div class="content">
            <%
            if '/post' in data['route']:
                include('admin/post.tpl')
            elif '/category' in data['route']:
                include('admin/category.tpl')
            end
            %>
        </div>
    </div>

    <div class="Listing region">
        %if 'items' in data:
        <ul class="list">
            %for item in data['items']:
            <li class="item">
                <a class="thumb" href="/{{data['type']}}/{{item['id']}}">
                    <img src="{{item['thumb']}}" />
                </a>
                <div>
                    <a class="title" href="/{{data['type']}}/{{item['id']}}">
                        {{item['title']}}
                    </a>
                    <span id="{{item['id']}}">
                        <script>
                            var date = (new Date('{{item["date"]}}')).toLocaleDateString()
                            $('.Listing .list .item #{{item["id"]}}').append(date)
                        </script>
                    </span>
                </div>
                <div class="edit">
                    <a href="/admin/{{data['type']}}/edit/{{item['id']}}">
                        <img src="/static/images/edit.png" />
                    </a>
                    <a href="/admin/{{data['type']}}/delete/{{item['id']}}">
                        <img src="/static/images/delete.png" />
                    </a>
                </div>
            </li>
            %end
        </ul>
        %end
        <div class="paginate region">
            <img onclick="paginate(`{{data['route']}}`)" src="/static/images/load-more.png"/>
        </div>
    </div>

</section>

 

/* public/styles/admin/index.css */
.Index .header-wrapper {
    background: var(--background-dark);
    margin-bottom: 20px;
}

.Index .header-wrapper header{
    display: grid;
    grid-template-columns: 25% auto 25%;
    align-items: center;
    padding: 10px 0;
}

.Index .header-wrapper header .logo{
    font: 24px/1.5 Limonf3;
}

.Index .header-wrapper header form{
    display: grid;
    grid-template-columns: 20% auto 20%;
}

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

.Index .header-wrapper header .logout{
    text-align: right;
}

.Index .header-wrapper header .logout a{
    color: white;
    font-size: 16px;
}

.Index .main{
    display: grid;
    grid-template-columns: 25% auto;
}

.Index .main .sidebar{
    background: var(--background-darker);
    margin-right: 10px;
}

.Index .main .sidebar .menu{
    display: grid;
    grid-template-columns: 25% auto;
    align-items: center;
    padding: 20px;
    grid-gap: 15px 10px;
    height: 400px;
}

.Index .main .sidebar .menu img{
    width: 100%;
    float: left;
}

.Index .main .sidebar .menu a{
    font: 18px/1.5 Oswald,Koulen;
}

.Index .Listing .list{
    display: grid;
    grid-template-columns: calc(50% - 5px) calc(50% - 5px);
    grid-gap: 10px;
    padding-top: 10px;
}

.Index .Listing .info{
    background: var(--background-darker);
    text-align: center;
    margin: 10px auto;
    padding: 5px;
}

.Index .Listing .list .item{
    display: grid;
    grid-template-columns: 22% 56% auto;
    background: var(--background-darker);
    grid-gap: 10px;
    align-items: center;
    padding-right: 10px;
}

.Index .Listing .item .thumb{
    position: relative;
    padding-top: 56.25%;
}

.Index .Listing .item .title{
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.Index .Listing .list .item .thumb img{
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    float: left;
}

.Index .Listing .list .item .edit{
    text-align: right;
}

.Index .Listing .list .item .edit img{
    width: 40px;
    visibility: hidden;
}

.Index .Listing .list .item:hover .edit img{
    visibility: visible;
}

.Index .paginate{
    text-align: center;
    padding: 5px 0 0;
    margin: 10px auto;
    background: var(--background-darker);
}

 

Vercel: https://khmerweb-vlog.vercel.app

GitHub: https://github.com/Sokhavuth/vlog