git clone https://github.com/arrowjs/CMS.git
cd CMS/
npm i
Click vào: Download Lite Version
https://graygrids.com/item/intimate-free-personal-blog-and-portfolio-bootstrap-template/
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
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
Chọn ảnh đại diện cho theme và copy vào /themes/frontend/intimate/
Tên phải đúng chuẩn: screenshot.png
Đường dẫn: /config/view.js
Tìm đến frontendTheme và sửa đúng như tên folder theme.
...
frontendTheme: 'Tên folder theme',
...
Trong admin, kiểm tra xem theme intimate đã được active chưa?
Trong frontend:
-
Sửa file index.twig trong themes/frontend/intimate/features/dashboard/
12345
-
Copy tất cả nội dung file index.html vào file _layout.twig
-
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 --> -
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> -
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
-
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 ‘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&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&spid=14019" target="_blank">KB3123303</a> adds the 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ó.
-
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.
-
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:
Mở file: /config/view.js
Tìm đến
...
pagination: {
numberItem: 5,
frontNumberItem: 5
}
...
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
Ta thấy blog được hiển thị ở trang chủ nên chúng ta sẽ chỉnh sửa trong /features/dashboard/
- 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
- 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ó frontend và backend, 2 cái đều render ra giao diện nên sẽ có 2 kiểu render res.frontend.render và res.backend.render.
-
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 } } -
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 %}





