Skip to content

Repository files navigation

Tạo blog từ ArrowCMS

Tải arrowCMS

git clone https://github.com/arrowjs/CMS.git
cd CMS/
npm i

Thêm 1 frontend theme mới

Bước 1: Tải template html

Click vào: Download Lite Version

https://graygrids.com/item/intimate-free-personal-blog-and-portfolio-bootstrap-template/

Bước 2: Giải nén và copy vào /themes/frontend/

test

Bước 3: Sửa tên folder (Cũng chính là tên theme). Ví dụ: intimate

hehe

Bước 4: Áp dụng theme đúng với cấu trúc

Cấu trúc cơ bản của 1 theme

.
├── assets ├── features ├── layouts ├── widgets ├── screenshot.png └── theme.json 
  • assets: Thư mục lưu các file css, jquery, image
  • features: Lưu các file theo features
  • layouts: Một số file khác
  • widgets:
  • screenshot.png: Ảnh đại diện của theme
  • theme.json: Để hệ thống có thể nhận được theme này.

Tạo folder, tạo file, di chuyển file để cho nó đúng với cấu trúc của theme.

.
├── assets
├── css
├── extras
├── fonts
├── img
└── js
├── features
└── dashboard
└── index.twig
├── layouts
├── _footer.twig
├── _header.twig
├── _layout.twig
└── _right_sidebar.twig
├── widgets ├── screenshot.png
└── theme.json 

cấu trúc

Buớc 5: Để nhận biết được 1 theme thì theme đó phải có file theme.json

Copy theme.json từ frontend theme khác và sửa cho đúng với theme mới

{
"information": {
"theme_name": "Intimate",
"theme_uri": "https://shapebootstrap.net/item/1524962-corlate-free-responsive-business-html-template",
"author": "SHAPEBOOTSTRAP",
"author_email": "support@shapebootstrap.net",
"version": "1.0",
"description": "Free Responsive Business HTML Template",
"license": "GNU General Public License v2 or later",
"license_uri": "http://www.gnu.org/licenses/gpl-2.0.html",
"tag": "bootstrap, corporate, html, responsive, corlate"
},
"sidebars": [
{
"name": "right-sidebar",
"title": "Right sidebar"
},
{
"name": "main-menu",
"title": "Main nenu"
}
]
}

Website sử dụng bao nhiêu sidebar thì chúng ta khai báo ở theme.json

Bước 6: Ảnh đại diện cho theme

Chọn ảnh đại diện cho theme và copy vào /themes/frontend/intimate/

Tên phải đúng chuẩn: screenshot.png

Bước 7: Đổi theme mặc định

Đường dẫn: /config/view.js

Tìm đến frontendTheme và sửa đúng như tên folder theme.

...
frontendTheme: 'Tên folder theme',
...

Bước 8: Kiểm tra

Trong admin, kiểm tra xem theme intimate đã được active chưa?

intimate

Trong frontend:

  • Sửa file index.twig trong themes/frontend/intimate/features/dashboard/

    12345
    
  • Chạy http://localhost:8000

frontend

Bước 9: Chia nhỏ file

  1. Copy tất cả nội dung file index.html vào file _layout.twig

  2. Copy phần header vào file _header.twig

    • Phần code mất trong file _layout.twig sẽ được thay thế bằng
    {% include "_header.twig" %}
    
    • File _header.twig
    <header class="site-header">
    <nav class="navbar navbar-default navbar-intimate role="
    data-offset-top="50" data-spy="affix">
    <div class="container">
    <div class="navbar-header">
    <!-- Start Toggle Nav For Mobile -->
    <button class="navbar-toggle" data-target="#navigation"
    data-toggle="collapse" type="button"><span class=
    "sr-only">Toggle navigation</span> <span class=
    "icon-bar"></span> <span class="icon-bar"></span>
    <span class="icon-bar"></span></button>
    <div class="logo">
    <a class="navbar-brand" href="index.html"><i class=
    "ico-3dglasses"></i></a>
    </div>
    </div><!-- Stat Search -->
    <div class="side">
    <a class="show-search"><i class="ico-search"></i></a>
    </div><!-- Form for navbar search area -->
    <form class="full-search">
    <div class="container">
    <div class="row">
    <input class="form-control" placeholder="Search"
    type="text"> <a class="close-search"><span class=
    "ico-times"></span></a>
    </div>
    </div>
    </form><!-- Search form ends -->
    <!-- Navigation Start -->
    <div class="navbar-collapse collapse" id="navigation">
    <ul class="nav navbar-nav navbar-right">
    <li class="dropdown dropdown-toggle active">
    <a data-toggle="dropdown" href=
    "index.html">Home</a>
    <ul class="dropdown-menu">
    <li>
    <a href="fullscreen-slider.html">Home -
    Fullscreen Slider</a>
    </li>
    <li>
    <a href="carousel-slider.html">Home - Post
    Carousel</a>
    </li>
    <li>
    <a href="index.html">Home - Default</a>
    </li>
    </ul>
    </li>
    <li class="dropdown dropdown-toggle">
    <a data-toggle="dropdown" href=
    "portfolio.html">Portfolio</a>
    <ul class="dropdown-menu">
    <li>
    <a href="portfolio-col-3.html">Portfolio 3
    column</a>
    </li>
    <li>
    <a href="portfolio-col-4.html">Portfolio 4
    column</a>
    </li>
    <li>
    <a href="portfolio-item.html">Single
    Project</a>
    </li>
    </ul>
    </li>
    <li class="dropdown dropdown-toggle">
    <a data-toggle="dropdown" href="#">Blog</a>
    <ul class="dropdown-menu">
    <li>
    <a href="blog.html">Blog View</a>
    </li>
    <li>
    <a href="single.html">Single Post</a>
    </li>
    </ul>
    </li>
    <li>
    <a href="contact.html">Contact</a>
    </li>
    <li>
    <a href="#">Download</a>
    </li>
    </ul>
    </div><!-- Navigation End -->
    </div>
    </nav><!-- Mobile Menu Start -->
    </header><!-- Header Section End -->
    <!-- Hero Area Start -->
    <section class="text-center" id="hero-area">
    <div class="container">
    <div class="row">
    <div class="col-md-12">
    <div class="intro-area">
    <h3>Welcome To</h3>
    <h2 class="page-title">Intimate Blog</h2>
    </div>
    </div>
    </div>
    </div>
    </section><!-- Hero Area End -->
    
  3. Copy footer vào file _footer.twig

    • Phần code mất trong file _layout.twig sẽ được thay thế bằng
    {% include "_footer.twig" %}
    
    • File _footer.twig
    <footer class="footer">
    <div class="container">
    <div class="row">
    <div class="col-md-12">
    <div class="footer-inner text-center">
    <div class="social-links">
    <a class="twitter social-link" data-placement="top"
    data-toggle="tooltip" href="#" title=
    "Twitter"><i class="fa fa-twitter"></i></a>
    <a class="facebook social-link" data-placement=
    "top" data-toggle="tooltip" href="#" title=
    "Facebook"><i class="fa fa-facebook"></i></a>
    <a class="google-plus social-link" data-placement=
    "top" data-toggle="tooltip" href="#" title=
    "Google+"><i class="fa fa-google-plus"></i></a>
    <a class="linkedin social-link" data-placement=
    "top" data-toggle="tooltip" href="#" title=
    "LinkedIn"><i class="fa fa-linkedin"></i></a>
    <a class="dribbble social-link" data-placement=
    "top" data-toggle="tooltip" href="#" title=
    "Dribbble"><i class="fa fa-dribbble"></i></a>
    <a class="pinterest social-link" data-placement=
    "top" data-toggle="tooltip" href="#" title=
    "Pinterest"><i class="fa fa-pinterest"></i></a>
    </div>
    <ul class="footer-menu">
    <li>
    <a href="#">Home</a>
    </li>
    <li>
    <a href="#">Portfolio</a>
    </li>
    <li>
    <a href="#">Blog</a>
    </li>
    <li>
    <a href="#">Contact</a>
    </li>
    <li>
    <a href="#">Download</a>
    </li>
    </ul>
    <div class="copyright">
    <p>Copyright © 2016 IntimateBlog. Designed and Developed by
    <a rel="nofollow" href="http://graygrids.com/">GrayGrids</a></p>
    </div>
    </div>
    </div>
    </div>
    </div>
    </footer>
    
  4. Copy tất cả nội dung trong div class="sidebar" vào file _right_sidebar.twig

    • Phần code mất trong file _layout.twig sẽ được thay thế bằng
    {% include "_right_sidebar.twig" %}
    
    • File _right_sidebar.twig

      Vì nội dung quá dài nên mình sẽ không thêm vào đây

  5. Copy chỗ thẻ article vào file index.twig

    Ở đây mình chỉ lấy 1 article, bỏ article còn lại.

    article cuối cùng là phân trang nên sẽ giữ lại

    File index.twig

    {% extends "_layout.twig" %}
    {% block content %}
    <article>
    <!-- Blog item Start -->
    <div class="blog-item-wrap">
    <!-- Post Format icon Start -->
    <div class="post-format">
    <span><i class="fa fa-camera"></i></span>
    </div><!-- Post Format icon End -->
    <h2 class="blog-title"><a href=
    "single.html">Personal Blog and Portfolio
    Template</a></h2><!-- Entry Meta Start-->
    <div class="entry-meta">
    <span class="meta-part"><i class=
    "ico-user"></i> <a href="#">James
    Maclern</a></span> <span class=
    "meta-part"><i class=
    "ico-calendar-alt-fill"></i> <a href=
    "#">January 7, 2015</a></span> <span class=
    "meta-part"><i class="ico-comments"></i>
    <a href="#">20</a></span> <span class=
    "meta-part"><i class="ico-tag"></i> <a href=
    "#">Tech</a></span> <span class=
    "meta-part"><i class="ico-star"></i> <a href=
    "#">7.5</a></span>
    </div><!-- Entry Meta End-->
    <!-- Feature inner Start -->
    <div class="feature-inner">
    <a data-lightbox="roadtrip" href=
    "img/blog/blog-01.jpg"><img alt="" src=
    "img/blog/blog-01.jpg"></a>
    </div><!-- Feature inner End -->
    <!-- Post Content Start -->
    <div class="post-content">
    <p>Internet Explorer has long been the bane of
    many Web developers’ existence, but here’s some
    news to brighten your day: Internet Explorer 8,
    9 and 10 are <a href=
    "https://www.microsoft.com/en-us/WindowsForBusiness/End-of-IE-support"
    target="_blank">reaching&nbsp;‘end of life’ on
    Tuesday</a>, meaning they’re no longer
    supported by Microsoft.</p>
    <p>A patch, <a href=
    "https://support.microsoft.com/en-us/kb/3123303?sd=rss&amp;spid=14019"
    target="_blank">which goes live on January
    12</a>, will nag Internet Explorer users on
    launch to upgrade to a modern browser. <a href=
    "https://support.microsoft.com/en-us/kb/3123303?sd=rss&amp;spid=14019"
    target="_blank">KB3123303</a> adds the&nbsp;nag
    box, which will appear for Windows 7 and Server
    2008 R2 users still using the old browsers
    after installing the update.</p>
    <p>It’s great news for developers who still
    need to target older browsers — not needing to
    worry about whether or not modern CSS works in
    these browsers is a dream, and it’s much closer
    with this move.</p>
    </div><!-- Post Content End -->
    <div class="entry-more">
    <div class="pull-left">
    <a class="btn btn-common" href=
    "single.html">Read More <i class=
    "ico-arrow-right"></i></a>
    </div>
    <div class="share-icon pull-right">
    <span class="socialShare"></span>
    </div>
    </div>
    </div><!-- Blog item End -->
    </article>
    <article>
    <!-- Pagination Start -->
    <ul class="pager">
    <li class="previous">
    <a href="#"><i class="ico-arrow-left"></i>
    Previous</a>
    </li>
    <li style="list-style: none"><span class=
    "active"><a href="#">1</a></span> <span><a href=
    "#">2</a></span> <span><a href="#">3</a></span>
    <span><a href="#">4</a></span> <span><a href=
    "#">5</a></span></li>
    <li class="next">
    <a href="#">Next <i class=
    "ico-arrow-right"></i></a>
    </li>
    </ul><!-- Pagination End -->
    </article>
    {% endblock %}
    
    • extends: nó sẽ kế thừa tất cả nội dung của _layout.twig
    • {% block content %} ... {% endblock %} : Để thay thế nội dung trong block content của thằng cha nó.
  6. File _layout.twig

    Mình chỉ copy phần thay đổi thôi

    <!-- Header Section Start -->
    {% include "_header.twig" %}
    <!-- Content Start -->
    <div id="content">
    <div class="container">
    <div class="row">
    <div class="col-md-8">
    <!-- Blog Article Start-->
    {% block content %}
    {% endblock %}
    <!-- Blog Article End-->
    </div>
    <div class="col-md-4">
    {% include "_right_sidebar.twig" %}
    </div>
    </div>
    </div>
    </div><!-- Content End -->
    <!-- Footer Start -->
    {% include "_footer.twig" %}
    <!-- Footer End -->
    

    Do index.twig kế thừa từ _layout.twig nên ở đây ta sẽ ko gọi include "index.twig".

    Ta sẽ dùng

    {% block content %}
    {% endblock %}
    

    Tại sao sử dụng {% block content %}... thì xem ở ngay trên sẽ thấy.

  7. Chỉnh lại đường dẫn cho file css, js

    Trong file _layout.twig

     <link href="css/bootstrap.min.css" madia="screen" rel="stylesheet" type="text/css">
    <script src="js/jquery-min.js" type="text/javascript"></script>
    

    Sửa thành

     <link href="/frontend/<folder theme>/assets/css/bootstrap.min.css" madia="screen" rel="stylesheet" type="text/css">
    <script src="/frontend/<folder theme>/assets/js/jquery-min.js" type="text/javascript"></script>
    

    Ở đây mình ví dụ 2 file, còn khi làm chúng ta sẽ sửa tất cả.

    Sau khi sửa xong giao diện sẽ như này:

Giao diện

Hiển thị blog, phân trang

Bước 1: Chỉnh sửa số post trên 1 trang

Mở file: /config/view.js

Tìm đến

...
pagination: {
numberItem: 5,
frontNumberItem: 5
}
...

Bước 2: Thêm post

Trong http://localhost:7000/admin/blog/posts

Chúng ta sẽ thêm post > 5 (số post trên 1 trang) để có ít nhất 2 trang

Bước 3: Hiển thị dữ liệu, phân trang

Ta thấy blog được hiển thị ở trang chủ nên chúng ta sẽ chỉnh sửa trong /features/dashboard/

  1. Chỉnh sửa file features/dashboard/frontend/controllers/index.js để lấy dữ liệu và trả về frontend
'use strict';
module.exports = function (controller, component, application) {
controller.index = function (req, res) {
let page = req.params.page || 1;
let itemOfPage = application.getConfig('pagination').frontNumberItem || 5;
let totalPage = 1;
application.feature.blog.actions.findAndCountAll({
where : {
published: 1,
type: 'post'
},
include: [{
model: application.models.user
}],
limit: itemOfPage,
offset: (page - 1) * itemOfPage
})
.then(data => {
totalPage = Math.ceil(data.count/itemOfPage);
res.frontend.render('index', {
postTitle: 'Blog page',
posts: data.rows,
page: page,
itemOfPage: itemOfPage,
totalPage: totalPage
})
})
};
};

Để có thể phân trang thì chúng ta cần 3 biến:

  • page: Số trang hiện tại. Mặc định là 1.

  • itemOfPage: Số post trên 1 trang được lấy từ config

  • totalPage: Tổng số trang

Dùng application để chạy function trong /features/blog/actions/post.js. Dùng Sequelize để lấy dữ liệu

application.feature.blog.actions.findAndCountAll({
where : {
published: 1,
type: 'post'
},
include: [{
model: application.models.user
}],
limit: itemOfPage,
offset: (page - 1) * itemOfPage
})
  • where: Truy vấn các trường trong CSDL
  • include: Do blog có foreignKey là 'created_by' chính là id của user nên ta dùng include để lấy thông tin user tạo blog
  • limit: Giới hạn post trên 1 trang
  • offset: Lấy từ post thứ mấy. Ví dụ: nếu có 20 post, có limit = 5, offset = 10 thì ta sẽ lấy được sp thứ: 10,11,12,13,14

Các câu lệnh truy vấn các bạn xem tại Sequelize

  1. Render ra frontend
.then(data => {
totalPage = Math.ceil(data.count/itemOfPage);
res.frontend.render('index', {
postTitle: 'Blog page',
posts: data.rows,
page: page,
itemOfPage: itemOfPage,
totalPage: totalPage
})
})
  • res.frontend.render: vì chúng ta có frontendbackend, 2 cái đều render ra giao diện nên sẽ có 2 kiểu render res.frontend.render và res.backend.render.
  1. Phân trang

    Để web có thể lấy được page hiện tại thì ta sử dụng đường dẫn /page/{số trang hiện tại}

    Ta sẽ thêm vào router.js

    "/page/:page": {
    get: {
    handler: controller.index
    }
    }
    
  2. Hiển thị dữ liệu frontend

  • Nội dung

    Chúng ta dùng hàm for để truy xuất từng phần tử

{% for post in posts %}
<article>
<!-- Blog item Start -->
<div class="blog-item-wrap">
<!-- Post Format icon Start -->
<div class="post-format">
<span><i class="fa fa-camera"></i></span>
</div><!-- Post Format icon End -->
<h2 class="blog-title"><a href=
"single.html">{{ post.title }}</a></h2><!-- Entry Meta Start-->
<div class="entry-meta">
<span class="meta-part">
<i class="ico-user"></i>
<a href="#">{{ post.user.display_name }}</a>
</span>
<span class="meta-part">
<i class="ico-calendar-alt-fill"></i>
<a href="#">{{ post.published_at | moment('DD-MM-YYYY') }}</a>
</span>
<span class="meta-part">
<i class="ico-comments"></i>
<a href="#">20</a>
</span>
<span class="meta-part">
<i class="ico-tag"></i>
<a href="#">Tech</a>
</span>
<span class="meta-part">
<i class="ico-star"></i>
<a href="#">7.5</a>
</span>
</div><!-- Entry Meta End-->
<!-- Feature inner Start -->
{% if post.image %}
<div class="feature-inner">
<a data-lightbox="roadtrip" href="{{ post.image }}">
<img alt="" src="{{ post.image }}">
</a>
</div>
{% endif %}
<!-- Feature inner End -->
<!-- Post Content Start -->
<div class="post-content">
{{ post.intro_text | safe }}
</div><!-- Post Content End -->
<div class="entry-more">
<div class="pull-left">
<a class="btn btn-common" href=
"single.html">Read More <i class=
"ico-arrow-right"></i></a>
</div>
<div class="share-icon pull-right">
<span class="socialShare"></span>
</div>
</div>
</div><!-- Blog item End -->
</article>
{% endfor %}
  • Phân trang
{% if totalPage > 1 %}
<article>
<!-- Pagination Start -->
<ul class="pager">
<li class="previous">
<a href="#"><i class="ico-arrow-left"></i>
Previous</a>
</li>
<li style="list-style: none">
{% for i in range(1, totalPage + 1) %}
{% if i === page %}
<span class="active">
<a href="javascript:void(0)">{{ i }}</a>
</span>
{% else %}
<span class="">
<a href="/page/{{ i }}">{{ i }}</a>
</span>
{% endif %}
{% endfor %}
</li>
<li class="next">
<a href="#">Next <i class=
"ico-arrow-right"></i></a>
</li>
</ul><!-- Pagination End -->
</article>
{% endif %}

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages