├── languages ├── .gitkeep ├── zh-CN.yml └── default.yml ├── scripts ├── .gitkeep ├── path_url.js ├── category.js └── home.js ├── index.html ├── layout ├── post.ejs ├── about.ejs ├── _partial │ ├── excerpt.ejs │ ├── pagination.ejs │ ├── footer.ejs │ ├── project-card.ejs │ ├── article-card.ejs │ ├── article.ejs │ ├── nav.ejs │ └── head.ejs ├── index.ejs ├── layout.ejs ├── tag.ejs ├── archive.ejs └── category.ejs ├── source ├── fonts │ ├── BebasNeue.otf │ └── MaturaMTScriptCapitals.ttf └── css │ ├── _partial │ ├── about.scss │ ├── tagcloud.scss │ ├── pagination.scss │ ├── footer.scss │ ├── archive.scss │ ├── nav.scss │ ├── project-card.scss │ └── article.scss │ ├── functions.scss │ ├── layout.scss │ ├── global.scss │ ├── index.scss │ ├── mixins.scss │ ├── reset.css │ └── fonts.scss ├── _config.yml └── readme.md /languages/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | hello 2 | -------------------------------------------------------------------------------- /layout/post.ejs: -------------------------------------------------------------------------------- 1 | <%- partial('_partial/article', { post: page }) %> -------------------------------------------------------------------------------- /source/fonts/BebasNeue.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esappear/hexo-theme-clover/HEAD/source/fonts/BebasNeue.otf -------------------------------------------------------------------------------- /scripts/path_url.js: -------------------------------------------------------------------------------- 1 | hexo.extend.helper.register('path_url', function(path){ 2 | return path.replace(/\/|\'|\s/g, '-'); 3 | }); -------------------------------------------------------------------------------- /layout/about.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 | <%- page.content %> 4 |
5 |
-------------------------------------------------------------------------------- /source/fonts/MaturaMTScriptCapitals.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esappear/hexo-theme-clover/HEAD/source/fonts/MaturaMTScriptCapitals.ttf -------------------------------------------------------------------------------- /languages/zh-CN.yml: -------------------------------------------------------------------------------- 1 | categories: 分类 2 | tags: 标签 3 | archive_a: 归档 4 | archive_b: 归档:%s 5 | page: 第 %d 页 6 | category: 分类 7 | tag: 标签 8 | other_category: 其他 -------------------------------------------------------------------------------- /source/css/_partial/about.scss: -------------------------------------------------------------------------------- 1 | .about { 2 | background-color: white; 3 | min-height: 300px; 4 | padding: 80px; 5 | font-size: 16px; 6 | line-height: 30px; 7 | } -------------------------------------------------------------------------------- /source/css/_partial/tagcloud.scss: -------------------------------------------------------------------------------- 1 | .tagcloud { 2 | background-color: white; 3 | padding: 60px; 4 | > a { 5 | display: inline-block; 6 | padding: 10px; 7 | } 8 | } -------------------------------------------------------------------------------- /layout/_partial/excerpt.ejs: -------------------------------------------------------------------------------- 1 | <% if (post.excerpt) { %> 2 | <%- post.excerpt %> 3 | <% } else { %> 4 | <%= (post.raw.match(/excerpts?:\s*([^\n]+)\n/) || ['', ''])[1] %> 5 | <% } %> -------------------------------------------------------------------------------- /languages/default.yml: -------------------------------------------------------------------------------- 1 | categories: Categories 2 | tags: Tags 3 | archive_a: Archives 4 | archive_b: "Archives: %s" 5 | page: Page %d 6 | category: Category 7 | tag: Tag 8 | other_category: Others -------------------------------------------------------------------------------- /layout/index.ejs: -------------------------------------------------------------------------------- 1 | <% page.posts.each(function(post){ %> 2 | <%- partial('_partial/' + (theme.card_style.home || 'project-card') , { post: post }) %> 3 | <% }) %> 4 | <%- partial('_partial/pagination') %> -------------------------------------------------------------------------------- /source/css/functions.scss: -------------------------------------------------------------------------------- 1 | .f-fl { 2 | float: left; 3 | } 4 | 5 | .f-fr { 6 | float: right; 7 | } 8 | 9 | .f-cf { 10 | &::after { 11 | content: ''; 12 | display:block; 13 | height: 0; 14 | visibility: hidden; 15 | clear: both; 16 | } 17 | } -------------------------------------------------------------------------------- /source/css/layout.scss: -------------------------------------------------------------------------------- 1 | #container { 2 | max-width: 980px; 3 | margin: 90px auto 75px; 4 | padding: 0 15px; 5 | @media screen and (max-width: 600px){ 6 | margin-top: 20px; 7 | margin-bottom: 20px; 8 | } 9 | } 10 | 11 | #panel { 12 | background-color: white; 13 | } -------------------------------------------------------------------------------- /layout/_partial/pagination.ejs: -------------------------------------------------------------------------------- 1 | <% if (page.prev || page.next) { %> 2 | 8 | <% } %> 9 | -------------------------------------------------------------------------------- /source/css/_partial/pagination.scss: -------------------------------------------------------------------------------- 1 | .pagination { 2 | padding: 20px; 3 | background-color: white; 4 | text-align: center; 5 | > .prev, > .next { 6 | margin: 0 10px; 7 | } 8 | > .page-number { 9 | margin: 0 10px; 10 | &.current { 11 | text-decoration: underline; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /source/css/global.scss: -------------------------------------------------------------------------------- 1 | a { 2 | color: #333; 3 | text-decoration: none; 4 | &:hover { 5 | opacity: .7; 6 | } 7 | } 8 | 9 | body { 10 | font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; 11 | } -------------------------------------------------------------------------------- /source/css/_partial/footer.scss: -------------------------------------------------------------------------------- 1 | #footer { 2 | margin-top: 80px; 3 | font-size: 14px; 4 | line-height: 22px; 5 | opacity: 0.8; 6 | color: #333; 7 | .copyright { 8 | float: right; 9 | } 10 | @media screen and (max-width: 800px){ 11 | margin-top: 20px; 12 | text-align: center; 13 | .copyright { 14 | display: block; 15 | float: none; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /layout/_partial/footer.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /layout/_partial/project-card.ejs: -------------------------------------------------------------------------------- 1 |
2 | <% if (post.photos[0]) { %> 3 |
4 | 5 |
6 | <% } %> 7 |
8 | <%= post.title %> 9 |
<%- partial('excerpt', { post: post }) %>
10 |

<%- date(post.date, 'MMM D, YYYY') %>

11 |
12 |
-------------------------------------------------------------------------------- /source/css/index.scss: -------------------------------------------------------------------------------- 1 | @import 'mixins.scss'; 2 | @import 'reset.css'; 3 | @import 'layout.scss'; 4 | @import 'global.scss'; 5 | @import 'fonts.scss'; 6 | @import 'functions.scss'; 7 | 8 | @import '_partial/nav.scss'; 9 | @import '_partial/footer.scss'; 10 | @import '_partial/pagination.scss'; 11 | @import '_partial/project-card.scss'; 12 | @import '_partial/article.scss'; 13 | @import '_partial/archive.scss'; 14 | @import '_partial/about.scss'; 15 | @import '_partial/tagcloud.scss'; -------------------------------------------------------------------------------- /source/css/mixins.scss: -------------------------------------------------------------------------------- 1 | // 左侧固定,右侧自适应的布局 2 | @mixin left-right-layout($leftWidth, $divide:0, $align:middle) { 3 | font-size: 0; 4 | line-height: 0; 5 | > .leftWrap { 6 | display: inline-block; 7 | vertical-align: $align; 8 | width: $leftWidth; 9 | } 10 | > .rightWrap { 11 | display: inline-block; 12 | vertical-align: $align; 13 | width: 100%; 14 | box-sizing: border-box; 15 | margin-left: -$leftWidth; 16 | padding-left: $leftWidth + $divide; 17 | } 18 | } -------------------------------------------------------------------------------- /layout/_partial/article-card.ejs: -------------------------------------------------------------------------------- 1 |
2 | <% if (post.photos[0]) { %> 3 |
4 | 5 |
6 | <% } %> 7 |
8 | <%= post.title %> 9 |
<%- partial('excerpt', { post: post }) %>
10 |

<%- date(post.date, 'MMM D, YYYY') %>

11 |
12 |
-------------------------------------------------------------------------------- /layout/layout.ejs: -------------------------------------------------------------------------------- 1 | <%- partial('_partial/head') %> 2 | 11 |
12 | <%- partial('_partial/nav') %> 13 |
<%- body %>
14 | <%- partial('_partial/footer') %> 15 |
16 | 17 | -------------------------------------------------------------------------------- /layout/_partial/article.ejs: -------------------------------------------------------------------------------- 1 |
2 |

<%= post.title %>

3 |

<%- date(post.date, 'MMM D, YYYY') %>

4 |
5 | <%- post.more %> 6 |
7 | 15 |
-------------------------------------------------------------------------------- /layout/tag.ejs: -------------------------------------------------------------------------------- 1 | <% if (page.tag) { %> 2 | <% page.posts.each(function(post){ %> 3 | <% var tag = _.find(theme.menu, function (item) { 4 | return item.path === '/tags/' + page.tag; 5 | }); %> 6 | <%- partial('_partial/' + (theme.card_style.tag || 'article-card'), { post: post }) %> 7 | <% }) %> 8 | <%- partial('_partial/pagination') %> 9 | <% } else { %> 10 |
11 | <%- tagcloud({ 12 | min_font: 12, 13 | max_font: 30, 14 | amount: 300, 15 | color: true, 16 | start_color: '#aaa', 17 | end_color: '#333', 18 | }) %> 19 |
20 | <% } %> -------------------------------------------------------------------------------- /source/css/_partial/archive.scss: -------------------------------------------------------------------------------- 1 | .archive { 2 | padding: 80px 160px; 3 | background-color: white; 4 | @media screen and (max-width: 600px){ 5 | padding: 20px; 6 | } 7 | } 8 | 9 | .archive-category { 10 | > .title { 11 | font-size: 28px; 12 | line-height: 40px; 13 | font-weight: 600; 14 | } 15 | > .menu { 16 | margin-bottom: 70px; 17 | > li { 18 | margin-top: 10px; 19 | font-size: 16px; 20 | line-height: 24px; 21 | display: flex; 22 | justify-content: space-between; 23 | line-height: 24px; 24 | > a { 25 | &:hover { 26 | opacity: 1; 27 | color: #f0534e; 28 | } 29 | } 30 | > span { 31 | opacity: .45; 32 | font-size: 14px; 33 | min-width: 90px; 34 | text-align: right; 35 | } 36 | } 37 | } 38 | &:last-child { 39 | > .menu { 40 | margin-bottom: 0; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /layout/_partial/nav.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /layout/archive.ejs: -------------------------------------------------------------------------------- 1 |
2 | <% 3 | var groupPosts = _.groupBy(page.posts.data, function (post) { 4 | return post.date.format('YYYY'); 5 | }); 6 | groupPosts = _.reduce(groupPosts, function (result, posts, year) { 7 | return result.concat({ 8 | posts: _.orderBy(posts, function (post) { 9 | return post.date; 10 | }, 'desc'), 11 | year: year, 12 | }) 13 | }, []); 14 | groupPosts = _.orderBy(groupPosts, 'year', 'desc'); 15 | %> 16 | <% _.forEach(groupPosts, function (group) { %> 17 |
18 |

<%= group.year %>

19 | 27 |
28 | <% }); %> 29 |
30 | <%- partial('_partial/pagination') %> -------------------------------------------------------------------------------- /layout/_partial/head.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <% 6 | var title = page.title; 7 | 8 | if (is_archive()){ 9 | title = __('archive_a'); 10 | 11 | if (is_month()){ 12 | title += ': ' + page.year + '/' + page.month; 13 | } else if (is_year()){ 14 | title += ': ' + page.year; 15 | } 16 | } else if (is_category()){ 17 | title = __('category') + ': ' + page.category; 18 | } else if (is_tag()){ 19 | title = __('tag') + ': ' + page.tag; 20 | } 21 | %> 22 | <% if (title){ %><%= title %> | <% } %><%= config.title %> 23 | 24 | <%- open_graph({twitter_id: theme.twitter, google_plus: theme.google_plus, fb_admins: theme.fb_admins, fb_app_id: theme.fb_app_id}) %> 25 | <% if (theme.favicon){ %> 26 | 27 | <% } %> 28 | 29 | 30 | 37 | <%- css('css/index') %> 38 | 39 | -------------------------------------------------------------------------------- /source/css/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v4.0 | 20180602 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | main, menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, main, menu, nav, section { 29 | display: block; 30 | } 31 | /* HTML5 hidden-attribute fix for newer browsers */ 32 | *[hidden] { 33 | display: none; 34 | } 35 | body { 36 | line-height: 1; 37 | } 38 | ol, ul { 39 | list-style: none; 40 | } 41 | blockquote, q { 42 | quotes: none; 43 | } 44 | blockquote:before, blockquote:after, 45 | q:before, q:after { 46 | content: ''; 47 | content: none; 48 | } 49 | table { 50 | border-collapse: collapse; 51 | border-spacing: 0; 52 | } -------------------------------------------------------------------------------- /source/css/fonts.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'BebasNeue'; 3 | src: url('/fonts/BebasNeue.otf'); 4 | } 5 | 6 | @font-face { 7 | font-family: 'MaturaScriptCapitals'; 8 | src: url('/fonts/MaturaMTScriptCapitals.ttf'); 9 | } 10 | 11 | @font-face { 12 | font-family: 'iconfont'; /* project id 861369 */ 13 | src: url('//at.alicdn.com/t/font_861369_9voy0xmnmvl.eot'); 14 | src: url('//at.alicdn.com/t/font_861369_9voy0xmnmvl.eot?#iefix') format('embedded-opentype'), 15 | url('//at.alicdn.com/t/font_861369_9voy0xmnmvl.woff') format('woff'), 16 | url('//at.alicdn.com/t/font_861369_9voy0xmnmvl.ttf') format('truetype'), 17 | url('//at.alicdn.com/t/font_861369_9voy0xmnmvl.svg#iconfont') format('svg'); 18 | } 19 | 20 | .iconfont{ 21 | font-family:"iconfont" !important; 22 | font-size:16px;font-style:normal; 23 | -webkit-font-smoothing: antialiased; 24 | -webkit-text-stroke-width: 0.2px; 25 | -moz-osx-font-smoothing: grayscale; 26 | &.icon-behance::before { 27 | content: '\e919'; 28 | } 29 | &.icon-lofter::before { 30 | content: '\e63c'; 31 | } 32 | &.icon-instagram::before { 33 | content: '\e626'; 34 | } 35 | &.icon-dribbble::before { 36 | content: '\e6c3'; 37 | } 38 | &.icon-github::before { 39 | content: '\e799'; 40 | } 41 | &.icon-arrow-left::before { 42 | content: '\e91a'; 43 | } 44 | &.icon-arrow-right::before { 45 | content: '\e636'; 46 | } 47 | } -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Custom nav 2 | nav: 3 | title: "Clover Tuan" 4 | 5 | favicon: "" 6 | 7 | # Custom background 8 | background: 9 | color: "#eff0f6" 10 | image: "" 11 | 12 | # Social media 13 | social: 14 | Dribbble: https://dribbble.com/clovertuan 15 | Behance: https://www.behance.net/clovertuan 16 | Lofter: http://clovertuan.lofter.com/ 17 | Instagram: https://www.instagram.com/clovertuan/ 18 | GitHub: https://github.com/cloverTuan 19 | 20 | # Custom footer 21 | mail: d.guangying@foxmail.com 22 | copyright: All rights reserved @Clover Tuan 23 | 24 | # Custom menu. You can specific the path or the card style (only useful for category page). 25 | # Two kinds of card style: 'project-card', 'article-card', 26 | # Never mind the name. 27 | menu: 28 | # Project: 29 | # path: /categories/Projects 30 | # card: project-card 31 | # Stuffs: 32 | # path: /tags/Stuffs 33 | # card: article-card 34 | Home: / 35 | Archive: /archives 36 | About: /about 37 | 38 | # Specific default categories or tags of home page. 39 | # Post which belongs to `category` or `tag` and don't belongs to `except_category` or `except_tag` will be filtered. 40 | home: 41 | # set card style of home page 42 | # category: Projects 43 | # tag: 算法 44 | # except_category: 树 45 | # except_tag: 46 | # - 总结 47 | # - css 48 | 49 | card_style: 50 | home: project-card 51 | archive: article-card 52 | tag: article-card 53 | category: article-card 54 | 55 | # category page 56 | category_generator: 57 | category_per_page: 3 58 | post_per_category: 3 59 | 60 | node_sass: 61 | outputStyle: nested 62 | precision: 5 63 | sourceComments: false -------------------------------------------------------------------------------- /source/css/_partial/nav.scss: -------------------------------------------------------------------------------- 1 | #nav { 2 | margin-bottom: 64px; 3 | > .header { 4 | margin-bottom: 10px; 5 | > .title { 6 | font-size: 45px; 7 | line-height: 53px; 8 | color: #333; 9 | font-family: MaturaScriptCapitals; 10 | &:hover { 11 | opacity: .7; 12 | } 13 | } 14 | } 15 | > .ctnWrap { 16 | display: flex; 17 | flex-wrap: wrap; 18 | justify-content: space-between; 19 | > .menu { 20 | // min-width: 320px; 21 | text-align: right; 22 | } 23 | @media screen and (max-width: 600px){ 24 | flex-direction: column; 25 | > .menu { 26 | text-align: center; 27 | margin-top: 10px; 28 | } 29 | } 30 | } 31 | .nav-menu { 32 | font-family: BebasNeue; 33 | font-size: 20px; 34 | line-height: 24px; 35 | color: #333; 36 | margin-left: 24px; 37 | &:first-child { 38 | margin-left: 0; 39 | } 40 | &.z-active { 41 | position: relative; 42 | &::after { 43 | content: ''; 44 | position: absolute; 45 | left: 0; 46 | right: 0; 47 | bottom: -4px; 48 | height: 2px; 49 | background-color: #333; 50 | } 51 | } 52 | @media screen and (max-width: 600px){ 53 | margin-left: 10px; 54 | font-size: 18px; 55 | } 56 | } 57 | .nav-icn { 58 | margin-right: 15px; 59 | line-height: 24px; 60 | &:last-child { 61 | margin-right: 0; 62 | } 63 | } 64 | @media screen and (max-width: 600px){ 65 | text-align: center; 66 | margin-bottom: 20px; 67 | > .ctnWrap { 68 | justify-content: space-around; 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /scripts/category.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assign = require('object-assign'); 4 | var pagination = require('hexo-pagination'); 5 | var _ = require('lodash'); 6 | 7 | hexo.config.category_generator = assign({ 8 | per_page: typeof hexo.config.per_page === "undefined" ? 10 : hexo.config.per_page 9 | }, hexo.config.category_generator); 10 | 11 | hexo.extend.generator.register('category', function(locals){ 12 | var config = this.config; 13 | var perPage = config.category_generator.per_page; 14 | var paginationDir = config.pagination_dir || 'page'; 15 | 16 | // var totalPosts = locals.posts.sort(config.category_generator.order_by || '-date'); 17 | // var totalPosts = _.sortBy(locals.posts.data, config.category_generator.order_by || function (post) { 18 | // return post.categories.data[0] ? post.categories.data[0].name : '-1'; 19 | // }); 20 | var rootPath = config.category_generator.path || 'categories'; 21 | 22 | return locals.categories.reduce(function(result, category){ 23 | if (!category.length) return result; 24 | 25 | var posts = category.posts.sort('-date'); 26 | var data = pagination(category.path, posts, { 27 | perPage: perPage, 28 | layout: ['category', 'archive', 'index'], 29 | format: paginationDir + '/%d/', 30 | data: { 31 | category: category.name 32 | } 33 | }); 34 | 35 | return result.concat(data); 36 | }, []).concat(pagination(rootPath, locals.posts.sort(config.category_generator.order_by || '-date'), { 37 | perPage: perPage, 38 | layout: ['category', 'archive', 'index'], 39 | format: paginationDir + '/%d/', 40 | data: { 41 | category: null, 42 | } 43 | })); 44 | }); -------------------------------------------------------------------------------- /layout/category.ejs: -------------------------------------------------------------------------------- 1 | <% if (page.category) { %> 2 | <% page.posts.each(function(post){ %> 3 | <%- partial('_partial/' + (theme.card_style.category || 'article-card'), { post: post }) %> 4 | <% }) %> 5 | <% } else { %> 6 | <% 7 | var CLOVER_OTHERS = '__CLOVER_OTHERS'; 8 | var totalPosts = _.orderBy(site.posts.data, function (post) { 9 | return post.categories.data[0] ? post.categories.data[0].name : CLOVER_OTHERS; 10 | }, 'asc'); 11 | var posts = page.current ? totalPosts.slice(config.per_page * (page.current - 1), config.per_page * page.current) : totalPosts; 12 | var groupPosts = _.groupBy(posts, function (post) { 13 | return post.categories.data[0] ? post.categories.data[0].name : CLOVER_OTHERS; 14 | }); 15 | groupPosts = _.reduce(groupPosts, function (result, posts, category) { 16 | return result.concat({ 17 | posts: _.orderBy(posts, function (post) { 18 | return post.date; 19 | }, 'desc'), 20 | category: category, 21 | }) 22 | }, []); 23 | groupPosts = _.orderBy(groupPosts, 'category', 'asc'); 24 | %> 25 |
26 | <% _.forEach(groupPosts, function (group) { %> 27 |
28 |

<%= group.category === CLOVER_OTHERS ? __('other_category') : group.category %>

29 | 37 |
38 | <% }); %> 39 |
40 | <% } %> 41 | <%- partial('_partial/pagination') %> -------------------------------------------------------------------------------- /source/css/_partial/project-card.scss: -------------------------------------------------------------------------------- 1 | .project-card { 2 | display: flex; 3 | justify-content: space-between; 4 | align-items: center; 5 | padding: 80px 100px; 6 | margin: 40px 0; 7 | background-color: white; 8 | color: #333; 9 | > .imgWrap { 10 | width: 320px; 11 | margin-right: 40px; 12 | background-color: #f8f8f8; 13 | > img { 14 | width: 100%; 15 | height: auto; 16 | display: block; 17 | } 18 | } 19 | > .ctnWrap { 20 | flex: 1; 21 | > .title { 22 | font-weight: 600; 23 | font-size: 28px; 24 | line-height: 40px; 25 | &:hover { 26 | opacity: 1; 27 | color: #f0534e; 28 | } 29 | } 30 | > .desc { 31 | font-size: 16px; 32 | line-height: 30px; 33 | margin-top: 20px; 34 | margin-bottom: 15px; 35 | } 36 | > .sub { 37 | font-size: 16px; 38 | line-height: 30px; 39 | opacity: .5; 40 | } 41 | } 42 | &.project-card-continuous { 43 | flex-direction: row-reverse; 44 | margin: 0; 45 | position: relative; 46 | > .imgWrap { 47 | margin-right: 0; 48 | margin-left: 40px; 49 | } 50 | &::after { 51 | content: ''; 52 | position: absolute; 53 | left: 100px; 54 | right: 100px; 55 | bottom: 0; 56 | height: 1px; 57 | background-color: #e5e5e5; 58 | } 59 | @media screen and (max-width: 600px) { 60 | flex-direction: column; 61 | padding: 20px; 62 | > .imgWrap { 63 | margin-left: 0; 64 | margin-bottom: 20px; 65 | } 66 | &::after { 67 | left: 20px; 68 | right: 20px; 69 | } 70 | } 71 | } 72 | @media screen and (max-width: 600px) { 73 | flex-direction: column; 74 | padding: 20px; 75 | margin: 10px 0; 76 | > .imgWrap { 77 | margin-left: 0; 78 | margin-right: 0; 79 | margin-bottom: 20px; 80 | width: 100%; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /scripts/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var pagination = require('hexo-pagination'); 3 | var assign = require('object-assign'); 4 | var _ = require('lodash'); 5 | 6 | hexo.config.index_generator = assign({ 7 | per_page: typeof hexo.config.per_page === "undefined" ? 10 : hexo.config.per_page 8 | }, hexo.config.index_generator); 9 | 10 | hexo.extend.generator.register('index', function(locals){ 11 | var config = this.config; 12 | var posts = (this.theme.config.home ? locals.posts.filter(getPostFilter(this.theme.config.home)): locals.posts).sort('-date'); 13 | var paginationDir = config.pagination_dir || 'page'; 14 | 15 | return pagination('', posts, { 16 | perPage: config.index_generator.per_page, 17 | layout: ['index', 'archive'], 18 | format: paginationDir + '/%d/', 19 | data: { 20 | __index: true 21 | } 22 | }); 23 | }); 24 | 25 | function getPostFilter(config) { 26 | var filter_categories = _.isString(config.category) ? [config.category] : config.category; 27 | var filter_tags = _.isString(config.tag) ? [config.tag] : config.tag; 28 | var except_categories = _.isString(config.except_category) ? [config.except_category] : config.except_category; 29 | var except_tags = _.isString(config.except_tag) ? [config.except_tag] : config.except_tag; 30 | return function (post) { 31 | // 没有category或tag的时候 只看 except_category 和 except_tag 32 | if (!filter_categories && !filter_tags) { 33 | return !(_.find(post.categories.data, function (category) { 34 | return _.includes(except_categories, category.name); 35 | }) || _.find(post.tags.data, function (tag) { 36 | return _.includes(except_tags, tag.name); 37 | })); 38 | } 39 | // 在category或tag中 且不在except_category或except_tag 中 40 | return (_.find(post.categories.data, function (category) { 41 | return _.includes(filter_categories, category.name); 42 | }) || _.find(post.tags.data, function (tag) { 43 | return _.includes(filter_tags, tag.name); 44 | })) && !(_.find(post.categories.data, function (category) { 45 | return _.includes(except_categories, category.name); 46 | }) || _.find(post.tags.data, function (tag) { 47 | return _.includes(except_tags, tag.name); 48 | })); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Clover 2 | ## [Preview](https://esappear.github.io/clover/) 3 | ![preview](https://media.githubusercontent.com/avatars/8626321?orig=1&token=ANM6mziZ-bdE9fPaDWu1LVN0JQ-Vz-k_ks5b0I9FwA%3D%3D) 4 | 5 | ## Prerequisite 6 | You got a blog project built by [Hexo](https://hexo.io). Your project directory should like this: 7 | ``` 8 | _config.yml node_modules package.json public scaffolds source themes 9 | ``` 10 | ## Installation 11 | - Clone the repository. 12 | ``` 13 | git clone https://github.com/esappear/hexo-theme-clover themes/clover 14 | ``` 15 | - Set theme in `_config.yml` file of the project root: 16 | ``` 17 | theme: clover 18 | ``` 19 | - Add `hexo-renderer-sass` 20 | ``` 21 | npm install hexo-renderer-sass --save 22 | ``` 23 | ## Features 24 | ### Free home page. 25 | You can set posts of specific categories or tags in home page. 26 | ``` 27 | home: 28 | # set card style of home page 29 | # card: project-card 30 | category: Projects 31 | tag: 32 | - js 33 | - css 34 | except_category: Something 35 | except_tag: 'someTag' 36 | ``` 37 | Post which belongs to `category` or `tag` and don't belongs to `except_category` or `except_tag` will be filtered. 38 | 39 | ### Page excerpt and photos 40 | You can set an excerpt or photos in `Front-matter`. 41 | ``` 42 | --- 43 | layout: post 44 | title: my_post_title 45 | excerpt: my_post_excerpt 46 | photos: [my_photo_url] 47 | --- 48 | ``` 49 | ### Tags page. 50 | - Create a page named tags 51 | ``` 52 | hexo new page "tags" 53 | ``` 54 | - Edit tags page, set page layout to `tag`. 55 | ``` 56 | --- 57 | layout: tag 58 | title: tags 59 | date: 2018-10-05 12:12:53 60 | --- 61 | ``` 62 | ### Categories page. 63 | - Create a page named categories 64 | ``` 65 | hexo new page "categories" 66 | ``` 67 | - Edit categories page, set page layout to `category`. 68 | ``` 69 | --- 70 | layout: category 71 | title: categories 72 | date: 2018-10-05 12:12:53 73 | --- 74 | ``` 75 | ### About page. 76 | - Create a page named about 77 | ``` 78 | hexo new page "about" 79 | ``` 80 | - Edit categories page, set page layout to `about`. 81 | ``` 82 | --- 83 | layout: about 84 | title: about 85 | date: 2018-10-05 12:12:53 86 | --- 87 | ``` 88 | 89 | ### Social Media 90 | ``` 91 | social: 92 | GitHub: your-url 93 | Dribbble: your-url 94 | Behance: your-url 95 | Lofter: your-url 96 | Instagram: your-url 97 | ``` 98 | 99 | ### Custom Menu 100 | ``` 101 | menu: 102 | Project: / 103 | Stuffs: /tags/Stuffs 104 | Archive: /archives 105 | About: /about 106 | ``` 107 | 108 | ### Card Style 109 | Two kinds of card style: `project-card` and `article-card`. (Never mind the name.) 110 | ``` 111 | card_style: 112 | home: project-card 113 | archive: article-card 114 | tag: article-card 115 | category: article-card 116 | ``` 117 | 118 | ### Code Highlight 119 | - You should disable the default highlight setting in `.config.yml` and then get gihub-style code highlight powered by `hight.js`. 120 | ``` 121 | highlight: 122 | enable: false 123 | ``` 124 | - declare language of code 125 | ```md 126 | ```js 127 | console.log('hello world); 128 | ``` 129 | -------------------------------------------------------------------------------- /source/css/_partial/article.scss: -------------------------------------------------------------------------------- 1 | $brand-color: #f0534e; 2 | .article { 3 | margin: 64px 0 80px; 4 | padding: 80px 100px 0; 5 | background-color: white; 6 | color: #333; 7 | font-size: 16px; 8 | line-height: 30px; 9 | > .title { 10 | font-size: 28px; 11 | line-height: 40px; 12 | margin-bottom: 10px; 13 | font-weight: 600; 14 | } 15 | > .sub { 16 | opacity: .5; 17 | margin-bottom: 20px; 18 | } 19 | > .content { 20 | padding-bottom: 64px; 21 | h1, h2, h3, h4, h5{ 22 | font-size:24px; 23 | font-weight: 600; 24 | line-height: 40px; 25 | margin-bottom: 15px; 26 | } 27 | 28 | p { 29 | font-size: 16px; 30 | line-height: 30px; 31 | margin-bottom: 15px; 32 | } 33 | 34 | pre, .highlight { 35 | overflow: auto;; 36 | padding: 0; 37 | color: #333; 38 | font-size: 13px; 39 | background: #f8f8f8; 40 | .gutter { 41 | text-align: right; 42 | pre { 43 | background-color: #f0f0f0; 44 | padding: 0 10px; 45 | } 46 | } 47 | .code { 48 | padding: 0 10px; 49 | } 50 | } 51 | .highlight { 52 | margin-bottom: 15px; 53 | } 54 | 55 | ul, ol { 56 | margin: 15px 0; 57 | margin-left:15px; 58 | > li { 59 | padding-left: 20px; 60 | position: relative; 61 | &::before { 62 | content: ''; 63 | position: absolute; 64 | left: 0; 65 | top: 15px; 66 | margin-top: -3px; 67 | width: 6px; 68 | height: 6px; 69 | border-radius: 100%; 70 | background-color: #444; 71 | } 72 | } 73 | } 74 | a { 75 | color: $brand-color; 76 | } 77 | 78 | strong { 79 | font-weight: 600; 80 | } 81 | 82 | 83 | figure > img { 84 | display: block; 85 | } 86 | 87 | figcaption { 88 | font-size: 14px; 89 | } 90 | 91 | blockquote { 92 | border-left: 4px solid #ddd; 93 | color: #7a7a7a; 94 | border-left: 5px solid #ccc; 95 | padding-left: 15px; 96 | font-size: 16px; 97 | margin-bottom: 15px; 98 | 99 | > :last-child { 100 | margin-bottom: 0; 101 | } 102 | } 103 | 104 | p code { 105 | padding: 2px 4px; 106 | word-wrap: break-word; 107 | color: #555; 108 | background: #eee; 109 | border-radius: 3px; 110 | font-size: 13px; 111 | } 112 | 113 | table { 114 | margin: 20px 0; 115 | width: 100%; 116 | border-collapse: collapse; 117 | border-spacing: 0; 118 | border: 1px solid #ddd; 119 | table-layout: fixed; 120 | word-wrap: break-all; 121 | >tbody>tr { 122 | &:nth-of-type(odd) { background-color: #f9f9f9; } 123 | &:hover { background-color: #f5f5f5; } 124 | } 125 | caption, th, td { 126 | padding: 5px; 127 | text-align: center; 128 | vertical-align: middle; 129 | font-weight: normal; 130 | } 131 | 132 | th, td { 133 | border-bottom: 3px solid #ddd; 134 | border-right: 1px solid #eee; 135 | } 136 | 137 | th { 138 | padding-bottom: 10px; 139 | font-weight: 700; 140 | } 141 | 142 | td { border-bottom-width: 1px; } 143 | } 144 | 145 | * { 146 | max-width: 100%; 147 | } 148 | } 149 | > footer { 150 | padding: 40px 0; 151 | border-top: solid 1px #eee; 152 | > .link { 153 | font-size: 16px; 154 | line-height: 22px; 155 | max-width: 50%; 156 | } 157 | } 158 | @media screen and (max-width: 600px) { 159 | padding: 20px 20px 0; 160 | margin: 20px 0; 161 | > footer { 162 | padding: 10px 0; 163 | } 164 | } 165 | } --------------------------------------------------------------------------------