├── LICENSE ├── README.md ├── assets ├── css │ ├── archives.css │ ├── base.css │ ├── common.css │ ├── index.css │ ├── kg.css │ ├── post.css │ ├── tag.css │ └── vue.css ├── js │ ├── highlight.js │ ├── index.js │ └── post.js ├── screenshot-desktop.jpg └── screenshot-mobile.jpg ├── custom-archives.hbs ├── custom-tags.hbs ├── default.hbs ├── index.hbs ├── package.json ├── page-archives.hbs ├── partials ├── header.hbs ├── loop.hbs ├── navigation.hbs └── pagination.hbs └── post.hbs /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2017 Ghost Foundation 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | 适用于Ghost博客系统的简约主题。 4 | 5 | # 预览 6 | PC端预览图 7 | 8 | ![YtiABt.png](https://s1.ax1x.com/2020/05/12/YtiABt.png) 9 | 10 | 移动端预览图 11 | 12 | ![YtFC5T.md.png](https://s1.ax1x.com/2020/05/12/YtFC5T.md.png) 13 | 14 | ## 特性 15 | 16 | * 风格简约 17 | * 代码高亮为vue风格 18 | * 布局自适应 19 | 20 | ## 使用 21 | 22 | 首先下载主题包↓ 23 | 24 | [旧版本](https://github.com/zhaohaodang/ghost-theme-tiny/archive/1.0.0.zip)(适合版本低于1.0的Ghost系统) 25 | 26 | [最新版本](https://github.com/zhaohaodang/ghost-theme-tiny/tags)(适合4.0版本的Ghost系统) 27 | 28 | 进入博客后台(博客地址+`/ghost`),点击左侧栏的小齿轮图标,点击`Themes`模块,然后点击底部`upload theme`按钮(记得active)。 29 | 30 | ## 开启评论或统计 31 | 默认不开启任何评论或统计,你可以在`{{ghost_head}}`为以下几个全局变量赋值,以开启对应评论或者统计: 32 | 33 | ```javascript 34 | 40 | ``` 41 | ## 开启归档和标签页面 42 | 1. 进入博客的后台 43 | 2. 点击左侧栏的Pages,新建一个page 44 | 3. 点击右侧的小齿轮,在底部为页面选择tags模板或者archives模板 45 | 4. 发布页面 46 | 47 | ## 注意 48 | 1. 随着ghost博客系统版本版本的更新,该主题可能已经不适合最新版本。 49 | 2. 页面头部的社交按钮超链接,请在代码里自行修改。 50 | 3. 任何问题可以在此提出 https://github.com/zhaohaodang/ghost-theme-tiny/issues 51 | -------------------------------------------------------------------------------- /assets/css/archives.css: -------------------------------------------------------------------------------- 1 | .archives-info time{ 2 | float: left; 3 | width: 50px; 4 | } 5 | .archives-info a{ 6 | float: left; 7 | width: 80%; 8 | transition: 0.3s; 9 | } 10 | .archives-info a:hover{ 11 | color:#42b983; 12 | } 13 | .archives-item{ 14 | margin-bottom: 15px; 15 | } 16 | .archives-year{ 17 | font-size: 20px; 18 | margin: 20px 0; 19 | } -------------------------------------------------------------------------------- /assets/css/base.css: -------------------------------------------------------------------------------- 1 | html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,sub,sup,tt,var,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block;}body{line-height:1;}ol,ul{list-style:none;}blockquote,q{quotes:none;}blockquote:before,blockquote:after,q:before,q:after{content:' ';content:none;}table{border-collapse:collapse;border-spacing:0;}body{font:12px/1.5 Helvetica,Arial,sans-serif;}h1,h2,h3,h4,h5,h6{font-weight:normal;}input{outline:0;}.hidden{float:left;width:0;height:0;overflow:hidden;}.hiddenText{text-indent:100%;white-space:nowrap;overflow:hidden;}.sans{font-family:'Microsoft Yahei','Hiragino Sans GB','WenQuanYi Micro Hei',STHeiti,\534E\6587\7EC6\9ED1,SimHei,Helvetica,Arial,sans-serif;}.smallSans{font-family:'Microsoft Yahei','Hiragino Sans GB','WenQuanYi Micro Hei',STHeiti,\534E\6587\7EC6\9ED1,SimSun,Helvetica,Arial,sans-serif;}.none{display:none;}.bold{font-weight:bold;}.center{text-align:center;}.clearfix:before,.clearfix:after{content:"";display:table;}.clearfix:after{clear:both;}.clearfix{zoom:1;}table{margin-left:1px;}table td,table th{padding:5px 10px;border:1px solid #ccc;vertical-align:middle;}a{text-decoration:none;} -------------------------------------------------------------------------------- /assets/css/common.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Roboto", "Helvetica Neue", "Hiragino Sans GB", "LiHei Pro", Arial, serif; 3 | text-rendering: optimizelegibility; 4 | -webkit-font-smoothing: antialiased; 5 | -moz-osx-font-smoothing: grayscale; 6 | font-weight: 400; 7 | font-size: 16px; 8 | word-spacing: 1px; 9 | color: #666; 10 | margin: 0; 11 | } 12 | img { 13 | border: none; 14 | } 15 | a { 16 | color: #666; 17 | text-decoration: none; 18 | transition: color 0.2s ease, border-color 0.2s ease; 19 | } 20 | .header { 21 | letter-spacing: 3px; 22 | margin: 80px auto 0px; 23 | text-align: center; 24 | } 25 | .header .logo{ 26 | width: 100px; 27 | height: 100px; 28 | overflow: hidden; 29 | border-radius: 50%; 30 | display: block; 31 | margin: 0 auto; 32 | margin-bottom: 10px; 33 | } 34 | .header .logo img{ 35 | width: 100%; 36 | height: 100%; 37 | } 38 | .header .tit { 39 | font-size: 15px; 40 | color: #444; 41 | } 42 | .nav{ 43 | position: fixed; 44 | top: 0; 45 | left: 0; 46 | border-bottom: 1px solid #ececec; 47 | box-shadow: 0 2px 5px #ececec; 48 | padding: 10px 0 10px 30px; 49 | z-index: 100; 50 | background: #fff; 51 | width: 100%; 52 | } 53 | .nav .nav-item { 54 | margin-right: 10px; 55 | } 56 | .nav .nav-current a{ 57 | color: #42b983; 58 | } 59 | .links { 60 | text-align: center; 61 | font-family: "Roboto", "Helvetica Neue", "Hiragino Sans GB", "LiHei Pro", Arial, serif; 62 | color: #999; 63 | font-size: 24px; 64 | margin: 0; 65 | } 66 | .links a { 67 | cursor: pointer; 68 | padding: 2px; 69 | margin: 0 3px; 70 | } 71 | .links a svg{ 72 | fill: #42b983; 73 | } 74 | .links img { 75 | width: 15px; 76 | height: 15px; 77 | } 78 | .header, 79 | h1, 80 | h2, 81 | h3, 82 | h4, 83 | h5, 84 | h6 { 85 | font-family: "Montserrat", "Helvetica Neue", "Hiragino Sans GB", "LiHei Pro", Arial, sans-serif; 86 | font-weight: 400; 87 | color: #444; 88 | } 89 | .main { 90 | max-width: 900px; 91 | margin: 0 auto; 92 | margin-top: 50px; 93 | padding: 0 30px 50px; 94 | position: relative; 95 | } 96 | @media screen and (max-width: 420px) { 97 | .header { 98 | margin: 70px auto 0px; 99 | } 100 | .header a { 101 | font-size: 14px; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /assets/css/index.css: -------------------------------------------------------------------------------- 1 | .post-list { 2 | list-style-type: none; 3 | padding: 0; 4 | padding-top: 4px; 5 | } 6 | 7 | .post-list li { 8 | position: relative; 9 | padding: 15px 0 15px; 10 | border-bottom: 0.5px solid #e6e6e6; 11 | } 12 | 13 | .post-list li:first-child { 14 | margin-top: -30px; 15 | } 16 | 17 | .post-list h2, 18 | .post-list h3 { 19 | letter-spacing: 1px; 20 | margin: 0; 21 | /* text-transform: uppercase; */ 22 | } 23 | 24 | .post-list h2 { 25 | font-size: 16px; 26 | letter-spacing: 1px; 27 | margin-left: 120px; 28 | } 29 | 30 | .post-list h2 a { 31 | color: #444; 32 | } 33 | 34 | .post-list h2 a:hover { 35 | color: #42b983; 36 | } 37 | 38 | .post-list h3 { 39 | font-size: 13px; 40 | color: #999; 41 | position: absolute; 42 | left: 0; 43 | top: 21px; 44 | } 45 | 46 | .post-list h2 .tag-box { 47 | float: right; 48 | /* margin-bottom: -5px; */ 49 | } 50 | 51 | .post-list h2 .tag-box a { 52 | font-size: 12px; 53 | transition: 0.3s; 54 | background: #42b983; 55 | padding: 2px 4px; 56 | margin-right: 4px; 57 | border-radius: 2px; 58 | color: #fff; 59 | } 60 | .post-list h2 .tag-box a:hover{ 61 | opacity: 0.8; 62 | } 63 | 64 | @media screen and (max-width: 420px) { 65 | .post-list h2 { 66 | font-size: 16px; 67 | margin-left: 0; 68 | } 69 | .post-list h2 a:hover { 70 | color: #42b983; 71 | } 72 | .post-list h3 { 73 | font-size: 11px; 74 | position: static; 75 | margin-bottom: 10px; 76 | } 77 | .post-list ul li { 78 | padding: 18px 0 20px; 79 | } 80 | .post-list ul li:first-child { 81 | margin-top: -35px; 82 | } 83 | } 84 | @media screen and (max-width: 750px){ 85 | .post-list h2 .tag-box { 86 | float: none; 87 | margin-bottom: -5px; 88 | } 89 | } 90 | .pagination { 91 | margin-top: 30px; 92 | text-align: center; 93 | } 94 | 95 | .pagination #newer { 96 | margin-right: 30px; 97 | } 98 | 99 | .pagination a { 100 | transition: 0.3s; 101 | } 102 | 103 | .pagination a:hover { 104 | color: #42b983; 105 | } -------------------------------------------------------------------------------- /assets/css/kg.css: -------------------------------------------------------------------------------- 1 | .kg-gallery-container { 2 | display: flex; 3 | flex-direction: column; 4 | } 5 | 6 | .kg-gallery-row { 7 | display: flex; 8 | flex-direction: row; 9 | justify-content: center; 10 | } 11 | 12 | .kg-gallery-image { 13 | cursor: pointer; 14 | } 15 | 16 | .kg-gallery-image img { 17 | width: 100%; 18 | height: 100%; 19 | } 20 | 21 | .kg-gallery-row:not(:first-of-type) { 22 | margin: 10px 0 0 0; 23 | } 24 | 25 | .kg-gallery-image:not(:first-of-type) { 26 | margin: 0 0 0 10px; 27 | } 28 | 29 | .kg-bookmark-card { 30 | overflow: hidden; 31 | border: 1px solid var(--light-gray-color); 32 | border-radius: 4px; 33 | } 34 | 35 | .kg-bookmark-container { 36 | display: flex; 37 | overflow: hidden; 38 | text-decoration: none !important; 39 | } 40 | 41 | .kg-bookmark-container::after { 42 | display: none; 43 | } 44 | 45 | .kg-bookmark-container:hover { 46 | opacity: 1; 47 | } 48 | 49 | .kg-bookmark-content { 50 | flex-grow: 1; 51 | overflow: hidden; 52 | padding: 25px; 53 | } 54 | 55 | .kg-bookmark-title { 56 | color: var(--darker-gray-color); 57 | font-size: 18px; 58 | line-height: 1.3; 59 | font-weight: 800; 60 | } 61 | 62 | .kg-bookmark-description { 63 | overflow: hidden; 64 | margin-top: 5px; 65 | color: var(--secondary-text-color); 66 | font-size: 14px; 67 | font-weight: 400; 68 | text-overflow: ellipsis; 69 | white-space: nowrap; 70 | } 71 | 72 | .kg-bookmark-metadata { 73 | display: flex; 74 | align-items: center; 75 | margin-top: 5px; 76 | font-size: 13px; 77 | line-height: 1; 78 | font-weight: 700; 79 | } 80 | 81 | .kg-bookmark-icon { 82 | margin-right: 5px; 83 | width: 20px; 84 | height: 20px; 85 | } 86 | 87 | .kg-bookmark-author, 88 | .kg-bookmark-publisher { 89 | color: var(--darker-gray-color); 90 | } 91 | 92 | .kg-bookmark-author+.kg-bookmark-publisher::before { 93 | content: "•"; 94 | padding: 0 5px; 95 | font-family: serif; 96 | } 97 | 98 | .kg-bookmark-thumbnail { 99 | position: relative; 100 | flex-shrink: 0; 101 | margin-left: 20px; 102 | width: 220px; 103 | } 104 | 105 | .kg-bookmark-thumbnail img { 106 | position: absolute; 107 | width: 100%; 108 | height: 100%; 109 | object-fit: cover; 110 | } 111 | 112 | @media (max-width: 767px) { 113 | .kg-bookmark-container { 114 | flex-direction: column; 115 | } 116 | .kg-bookmark-thumbnail { 117 | margin-left: 0; 118 | width: 100%; 119 | height: 200px; 120 | } 121 | } 122 | 123 | .kg-image { 124 | margin-right: auto; 125 | margin-left: auto; 126 | } 127 | 128 | .kg-canvas { 129 | display: grid; 130 | grid-template-columns: [full-start] minmax(5vw, auto) [wide-start] minmax(auto, 100px) [main-start] min(720px, calc(100% - 10vw)) [main-end] minmax(auto, 100px) [wide-end] minmax(5vw, auto) [full-end]; 131 | } 132 | 133 | .kg-canvas>* { 134 | grid-column: main-start/main-end; 135 | } 136 | 137 | .kg-width-wide { 138 | grid-column: wide-start/wide-end; 139 | } 140 | 141 | .kg-width-full { 142 | grid-column: full-start/full-end; 143 | } -------------------------------------------------------------------------------- /assets/css/post.css: -------------------------------------------------------------------------------- 1 | .gutter pre { 2 | color: #999; 3 | } 4 | 5 | pre { 6 | color: #525252; 7 | } 8 | 9 | pre .function .keyword, 10 | pre .constant { 11 | color: #0092db; 12 | } 13 | 14 | pre .keyword, 15 | pre .attribute { 16 | color: #e96900; 17 | } 18 | 19 | pre .number, 20 | pre .literal { 21 | color: #ae81ff; 22 | } 23 | 24 | pre .tag, 25 | pre .tag .title, 26 | pre .change, 27 | pre .winutils, 28 | pre .flow, 29 | pre .lisp .title, 30 | pre .clojure .built_in, 31 | pre .nginx .title, 32 | pre .tex .special { 33 | color: #2973b7; 34 | } 35 | 36 | pre .class .title { 37 | color: #fff; 38 | } 39 | 40 | pre .symbol, 41 | pre .symbol .string, 42 | pre .value, 43 | pre .regexp { 44 | color: #42b983; 45 | } 46 | 47 | pre .title { 48 | color: #a6e22e; 49 | } 50 | 51 | pre .tag .value, 52 | pre .string, 53 | pre .subst, 54 | pre .haskell .type, 55 | pre .preprocessor, 56 | pre .ruby .class .parent, 57 | pre .built_in, 58 | pre .sql .aggregate, 59 | pre .django .template_tag, 60 | pre .django .variable, 61 | pre .smalltalk .class, 62 | pre .javadoc, 63 | pre .django .filter .argument, 64 | pre .smalltalk .localvars, 65 | pre .smalltalk .array, 66 | pre .attr_selector, 67 | pre .pseudo, 68 | pre .addition, 69 | pre .stream, 70 | pre .envvar, 71 | pre .apache .tag, 72 | pre .apache .cbracket, 73 | pre .tex .command, 74 | pre .prompt { 75 | color: #42b983; 76 | } 77 | 78 | pre .comment, 79 | pre .java .annotation, 80 | pre .python .decorator, 81 | pre .template_comment, 82 | pre .pi, 83 | pre .doctype, 84 | pre .deletion, 85 | pre .shebang, 86 | pre .apache .sqbracket, 87 | pre .tex .formula { 88 | color: #b3b3b3; 89 | } 90 | 91 | pre .coffeescript .javascript, 92 | pre .javascript .xml, 93 | pre .tex .formula, 94 | pre .xml .javascript, 95 | pre .xml .vbscript, 96 | pre .xml .css, 97 | pre .xml .cdata { 98 | opacity: 0.5; 99 | } 100 | 101 | .post { 102 | position: relative; 103 | padding-bottom: 30px; 104 | margin-bottom: 30px; 105 | border-bottom: 1px solid #e6e6e6; 106 | } 107 | 108 | .post h1, 109 | .post h2 { 110 | /* text-transform: uppercase; */ 111 | } 112 | 113 | .post h1 a:hover, 114 | .post h2 a:hover { 115 | border-bottom: 3px solid #666; 116 | } 117 | 118 | .post h1 { 119 | font-size: 32px; 120 | margin: 0 0 45px; 121 | letter-spacing: 1px; 122 | } 123 | 124 | .post h2 { 125 | font-size: 24px; 126 | margin: 60px 0 30px; 127 | position: relative; 128 | } 129 | 130 | .post h2:before { 131 | content: ''; 132 | border-left: 5px solid #42b983; 133 | position: absolute; 134 | left: -15px; 135 | height: 75%; 136 | top: 12%; 137 | } 138 | 139 | .post h3 { 140 | margin: 30px 0 15px; 141 | } 142 | 143 | .post .date { 144 | font-family: "Montserrat", "Helvetica Neue", "Hiragino Sans GB", "LiHei Pro", Arial, sans-serif; 145 | font-size: 13px; 146 | color: #999; 147 | margin: 0 0 30px; 148 | letter-spacing: 1px; 149 | } 150 | 151 | .post .content { 152 | text-align: left; 153 | line-height: 1.8em; 154 | } 155 | 156 | .post .content p, 157 | .post .content ul, 158 | .post .content ol { 159 | margin: 1em 0 1.5em; 160 | } 161 | 162 | .post .content strong { 163 | font-weight: 600; 164 | color: #444; 165 | } 166 | 167 | .post .content ol { 168 | padding-left: 1.6em; 169 | } 170 | 171 | .post .content ul { 172 | padding-left: 15px; 173 | list-style-type: none; 174 | } 175 | 176 | .post .content ul li:before { 177 | position: absolute; 178 | font-weight: 600; 179 | content: " · "; 180 | margin: 0; 181 | left: 0; 182 | } 183 | 184 | .post .content a { 185 | color: #42b983; 186 | border-bottom: 2px solid transparent; 187 | } 188 | 189 | .post .content a:hover { 190 | color: #0fe282; 191 | border-bottom-color: #0fe282; 192 | } 193 | 194 | .post .content .highlight, 195 | .post .content .highlight table { 196 | margin: 0; 197 | width: 100%; 198 | } 199 | 200 | .post .content .highlight { 201 | overflow-x: auto; 202 | } 203 | 204 | .post .content .highlight table, 205 | .post .content .highlight tr, 206 | .post .content .highlight td { 207 | padding: 0; 208 | border-collapse: collapse; 209 | } 210 | 211 | .post .content code { 212 | font-family: "Roboto Mono", "Menlo", "Consolas", monospace; 213 | font-size: 13px; 214 | background-color: #f6f6f6; 215 | /* padding: 3px 10px; 216 | margin: 0 5px;*/ 217 | border-radius: 2px; 218 | } 219 | 220 | .post .content pre { 221 | font-family: "Roboto Mono", "Menlo", "Consolas", monospace; 222 | font-size: 13px; 223 | overflow-x: auto; 224 | text-align: left; 225 | padding: 15px 25px; 226 | background-color: #f6f6f6; 227 | line-height: 1.5em; 228 | } 229 | 230 | .post .content .code pre { 231 | border-top-right-radius: 2px; 232 | border-bottom-right-radius: 2px; 233 | } 234 | 235 | .post .content .gutter pre { 236 | padding: 15px 0 15px 15px; 237 | color: #75715e; 238 | border-top-left-radius: 2px; 239 | border-bottom-left-radius: 2px; 240 | } 241 | 242 | .post .content blockquote { 243 | margin: 2em 0; 244 | padding-left: 10px; 245 | border-left: 5px solid #e6e6e6; 246 | } 247 | 248 | .post .content blockquote p { 249 | font-size: 17px; 250 | font-style: italic; 251 | line-height: 1.8em; 252 | color: #999; 253 | } 254 | 255 | .post img { 256 | display: block; 257 | max-width: 100%; 258 | height: auto; 259 | } 260 | 261 | .blog-nav { 262 | position: fixed; 263 | bottom: 20px; 264 | height: 20px; 265 | line-height: 20px; 266 | font-family: "Montserrat", "Helvetica Neue", "Hiragino Sans GB", "LiHei Pro", Arial, sans-serif; 267 | font-size: 15px; 268 | color: #999; 269 | text-decoration: none; 270 | cursor: pointer; 271 | letter-spacing: 1px; 272 | border-bottom: 3px solid transparent; 273 | } 274 | 275 | .blog-nav:hover { 276 | color: #333; 277 | border-bottom-color: #333; 278 | } 279 | 280 | #newer { 281 | left: 40px; 282 | } 283 | 284 | #older { 285 | right: 40px; 286 | } 287 | 288 | .show-comments { 289 | font-family: "Montserrat", "Helvetica Neue", "Hiragino Sans GB", "LiHei Pro", Arial, sans-serif; 290 | text-align: center; 291 | } 292 | 293 | .show-comments a { 294 | color: #999; 295 | cursor: pointer; 296 | } 297 | 298 | .show-comments a:hover { 299 | color: #666; 300 | } 301 | 302 | @media screen and (max-width: 900px) { 303 | .post { 304 | /* padding-bottom: 80px; */ 305 | } 306 | .blog-nav { 307 | position: absolute; 308 | bottom: 30px; 309 | } 310 | #newer { 311 | left: 0; 312 | } 313 | #older { 314 | right: 0; 315 | } 316 | } 317 | 318 | @media screen and (max-width: 420px) { 319 | .main { 320 | margin-top: 32px; 321 | } 322 | .post h1 { 323 | font-size: 24px; 324 | margin: 0 0 30px; 325 | } 326 | .post h2 { 327 | font-size: 20px; 328 | margin: 30px 0 15px; 329 | } 330 | .post h3 { 331 | font-size: 16px; 332 | line-height: 1.3em; 333 | } 334 | .post .date { 335 | font-size: 12px; 336 | margin: 0 0 20px; 337 | } 338 | .post .content { 339 | font-size: 15px; 340 | } 341 | .post .content pre { 342 | font-size: 12px; 343 | } 344 | .post .content blockquote p { 345 | font-size: 16px; 346 | } 347 | .blog-nav { 348 | font-size: 14px; 349 | color: #444; 350 | } 351 | } 352 | 353 | .read-next-story h2 { 354 | margin-bottom: 10px; 355 | } 356 | 357 | .read-next-story h2 span { 358 | color: #42b983; 359 | } -------------------------------------------------------------------------------- /assets/css/tag.css: -------------------------------------------------------------------------------- 1 | .tags .tag-box { 2 | margin-top: 10px; 3 | } 4 | 5 | .tags .tag-box a { 6 | display: inline-block; 7 | background: #42b983; 8 | padding: 2px 4px; 9 | border-radius: 4px; 10 | color: #fff; 11 | transition: 0.3s; 12 | } 13 | 14 | .tags .tag-box a:hover { 15 | opacity: 0.8; 16 | } 17 | 18 | .tags .tag-box a:not(:first-child) { 19 | margin-left: 6px; 20 | } -------------------------------------------------------------------------------- /assets/css/vue.css: -------------------------------------------------------------------------------- 1 | .markdown-section { 2 | margin: 0 auto; 3 | max-width: 800px; 4 | padding: 30px 15px 40px; 5 | position: relative 6 | } 7 | .markdown-section>* { 8 | box-sizing: border-box; 9 | font-size: inherit 10 | } 11 | .markdown-section>:first-child { 12 | margin-top: 0 !important 13 | } 14 | .markdown-section hr { 15 | border: none; 16 | border-bottom: 1px solid #eee; 17 | margin: 2em 0 18 | } 19 | .markdown-section table { 20 | border-collapse: collapse; 21 | border-spacing: 0; 22 | display: block; 23 | margin-bottom: 16px; 24 | margin-bottom: 1rem; 25 | overflow: auto; 26 | width: 100% 27 | } 28 | .markdown-section th { 29 | font-weight: 700 30 | } 31 | .markdown-section td, .markdown-section th { 32 | border: 1px solid #ddd; 33 | padding: 6px 13px 34 | } 35 | .markdown-section tr { 36 | border-top: 1px solid #ccc 37 | } 38 | .markdown-section p.tip, .markdown-section tr:nth-child(2n) { 39 | background-color: #f8f8f8 40 | } 41 | .markdown-section p.tip { 42 | border-bottom-right-radius: 2px; 43 | border-left: 4px solid #f66; 44 | border-top-right-radius: 2px; 45 | margin: 2em 0; 46 | padding: 12px 24px 12px 30px; 47 | position: relative 48 | } 49 | .markdown-section p.tip code { 50 | background-color: #efefef 51 | } 52 | .markdown-section p.tip em { 53 | color: #34495e 54 | } 55 | .markdown-section p.tip:before { 56 | background-color: #f66; 57 | border-radius: 100%; 58 | color: #fff; 59 | content: "!"; 60 | font-family: Dosis, Source Sans Pro, Helvetica Neue, Arial, sans-serif; 61 | font-size: 14px; 62 | font-weight: 700; 63 | left: -12px; 64 | line-height: 20px; 65 | position: absolute; 66 | width: 20px; 67 | height: 20px; 68 | text-align: center; 69 | top: 14px 70 | } 71 | .markdown-section p.warn { 72 | background: rgba(66, 185, 131, .1); 73 | border-radius: 2px; 74 | padding: 16px; 75 | padding: 1rem 76 | } 77 | body.close .sidebar { 78 | -webkit-transform: translateX(-300px); 79 | transform: translateX(-300px) 80 | } 81 | body.close .sidebar-toggle { 82 | width: auto 83 | } 84 | body.close .content { 85 | left: 0 86 | } 87 | @media print { 88 | .app-nav, .github-corner, .sidebar, .sidebar-toggle { 89 | display: none 90 | } 91 | } 92 | @media screen and (max-width:768px) { 93 | .github-corner, .sidebar, .sidebar-toggle { 94 | position: fixed 95 | } 96 | .app-nav { 97 | margin-top: 16px 98 | } 99 | .app-nav li ul { 100 | top: 30px 101 | } 102 | main { 103 | height: auto; 104 | overflow-x: hidden 105 | } 106 | .sidebar { 107 | left: -300px; 108 | transition: -webkit-transform .25s ease-out; 109 | transition: transform .25s ease-out; 110 | transition: transform .25s ease-out, -webkit-transform .25s ease-out 111 | } 112 | .content { 113 | left: 0; 114 | max-width: 100vw; 115 | position: static; 116 | transition: -webkit-transform .25s ease; 117 | transition: transform .25s ease; 118 | transition: transform .25s ease, -webkit-transform .25s ease 119 | } 120 | .app-nav, .github-corner { 121 | transition: -webkit-transform .25s ease-out; 122 | transition: transform .25s ease-out; 123 | transition: transform .25s ease-out, -webkit-transform .25s ease-out 124 | } 125 | .sidebar-toggle { 126 | background-color: transparent; 127 | width: auto 128 | } 129 | body.close .sidebar { 130 | -webkit-transform: translateX(300px); 131 | transform: translateX(300px) 132 | } 133 | body.close .sidebar-toggle { 134 | background-color: hsla(0, 0%, 100%, .8); 135 | transition: background-color 1s; 136 | width: 284px 137 | } 138 | body.close .content { 139 | -webkit-transform: translateX(300px); 140 | transform: translateX(300px) 141 | } 142 | body.close .app-nav, body.close .github-corner { 143 | display: none 144 | } 145 | .github-corner .octo-arm { 146 | -webkit-animation: a .56s ease-in-out; 147 | animation: a .56s ease-in-out 148 | } 149 | .github-corner:hover .octo-arm { 150 | -webkit-animation: none; 151 | animation: none 152 | } 153 | } 154 | @-webkit-keyframes a { 155 | 0%, to { 156 | -webkit-transform: rotate(0); 157 | transform: rotate(0) 158 | } 159 | 20%, 60% { 160 | -webkit-transform: rotate(-25deg); 161 | transform: rotate(-25deg) 162 | } 163 | 40%, 80% { 164 | -webkit-transform: rotate(10deg); 165 | transform: rotate(10deg) 166 | } 167 | } 168 | @keyframes a { 169 | 0%, to { 170 | -webkit-transform: rotate(0); 171 | transform: rotate(0) 172 | } 173 | 20%, 60% { 174 | -webkit-transform: rotate(-25deg); 175 | transform: rotate(-25deg) 176 | } 177 | 40%, 80% { 178 | -webkit-transform: rotate(10deg); 179 | transform: rotate(10deg) 180 | } 181 | } 182 | section.cover { 183 | -webkit-box-align: center; 184 | -ms-flex-align: center; 185 | align-items: center; 186 | background-position: 50%; 187 | background-repeat: no-repeat; 188 | background-size: cover; 189 | height: 100vh; 190 | display: none 191 | } 192 | section.cover .cover-main { 193 | -webkit-box-flex: 1; 194 | -ms-flex: 1; 195 | flex: 1; 196 | margin: -20px 16px 0; 197 | text-align: center; 198 | z-index: 1 199 | } 200 | section.cover a { 201 | color: inherit 202 | } 203 | section.cover a, section.cover a:hover { 204 | text-decoration: none 205 | } 206 | section.cover p { 207 | line-height: 24px; 208 | line-height: 1.5rem; 209 | margin: 1em 0 210 | } 211 | section.cover h1 { 212 | color: inherit; 213 | font-size: 40px; 214 | font-size: 2.5rem; 215 | font-weight: 300; 216 | margin: 10px 0 40px; 217 | margin: .625rem 0 2.5rem; 218 | position: relative; 219 | text-align: center 220 | } 221 | section.cover h1 a { 222 | display: block 223 | } 224 | section.cover h1 small { 225 | bottom: -7px; 226 | bottom: -.4375rem; 227 | font-size: 16px; 228 | font-size: 1rem; 229 | position: absolute 230 | } 231 | section.cover blockquote { 232 | font-size: 24px; 233 | font-size: 1.5rem; 234 | text-align: center 235 | } 236 | section.cover ul { 237 | line-height: 1.8; 238 | list-style-type: none; 239 | margin: 1em auto; 240 | max-width: 500px; 241 | padding: 0 242 | } 243 | section.cover .cover-main>p:last-child a { 244 | border-color: #42b983; 245 | border: 1px solid var(--theme-color, #42b983); 246 | border-radius: 2rem; 247 | box-sizing: border-box; 248 | color: #42b983; 249 | color: var(--theme-color, #42b983); 250 | display: inline-block; 251 | font-size: 16.8px; 252 | font-size: 1.05rem; 253 | letter-spacing: 1.6px; 254 | letter-spacing: .1rem; 255 | margin-right: 16px; 256 | margin-right: 1rem; 257 | padding: .75em 32px; 258 | padding: .75em 2rem; 259 | text-decoration: none; 260 | transition: all .15s ease 261 | } 262 | section.cover .cover-main>p:last-child a:last-child { 263 | background-color: #42b983; 264 | background-color: var(--theme-color, #42b983); 265 | color: #fff; 266 | margin-right: 0 267 | } 268 | section.cover .cover-main>p:last-child a:last-child:hover { 269 | color: inherit; 270 | opacity: .8 271 | } 272 | section.cover .cover-main>p:last-child a:hover { 273 | color: inherit 274 | } 275 | section.cover blockquote>p>a { 276 | border-bottom: 2px solid #42b983; 277 | border-bottom: 2px solid var(--theme-color, #42b983); 278 | transition: color .3s 279 | } 280 | section.cover blockquote>p>a:hover { 281 | color: #42b983; 282 | color: var(--theme-color, #42b983) 283 | } 284 | section.cover.show { 285 | display: -webkit-box; 286 | display: -ms-flexbox; 287 | display: flex 288 | } 289 | section.cover.has-mask .mask { 290 | background-color: #fff; 291 | opacity: .8; 292 | position: absolute; 293 | width: 100%; 294 | height: 100% 295 | } 296 | .sidebar, body { 297 | background-color: #fff 298 | } 299 | .sidebar { 300 | color: #364149 301 | } 302 | .sidebar li { 303 | margin: 6px 0 6px 15px 304 | } 305 | .sidebar ul li a { 306 | color: #505d6b; 307 | font-size: 14px; 308 | font-weight: 400; 309 | overflow: hidden; 310 | text-decoration: none; 311 | text-overflow: ellipsis; 312 | white-space: nowrap 313 | } 314 | .sidebar ul li a:hover { 315 | text-decoration: underline 316 | } 317 | .sidebar ul li ul { 318 | padding: 0 319 | } 320 | .sidebar ul li.active>a { 321 | border-right: 2px solid; 322 | color: #42b983; 323 | color: var(--theme-color, #42b983); 324 | font-weight: 600 325 | } 326 | .app-sub-sidebar .section-link:before { 327 | content: "-"; 328 | padding-right: 4px 329 | } 330 | .markdown-section h1, .markdown-section h2, .markdown-section h3, .markdown-section h4, .markdown-section strong { 331 | color: #2c3e50; 332 | font-weight: 600 333 | } 334 | .markdown-section a { 335 | color: #42b983; 336 | color: var(--theme-color, #42b983); 337 | font-weight: 600 338 | } 339 | .markdown-section h1 { 340 | font-size: 32px; 341 | font-size: 2rem; 342 | margin: 0 0 16px; 343 | margin: 0 0 1rem 344 | } 345 | .markdown-section h2 { 346 | font-size: 28px; 347 | font-size: 1.75rem; 348 | margin: 45px 0 12.8px; 349 | margin: 45px 0 .8rem 350 | } 351 | .markdown-section h3 { 352 | font-size: 24px; 353 | font-size: 1.5rem; 354 | margin: 40px 0 9.6px; 355 | margin: 40px 0 .6rem 356 | } 357 | .markdown-section h4 { 358 | font-size: 20px; 359 | font-size: 1.25rem 360 | } 361 | .markdown-section h5, .markdown-section h6 { 362 | font-size: 16px; 363 | font-size: 1rem 364 | } 365 | .markdown-section h6 { 366 | color: #777 367 | } 368 | .markdown-section figure, .markdown-section ol, .markdown-section p, .markdown-section ul { 369 | margin: 1.2em 0 370 | } 371 | .markdown-section ol, .markdown-section p, .markdown-section ul { 372 | line-height: 25.6px; 373 | line-height: 1.6rem; 374 | word-spacing: .8px; 375 | word-spacing: .05rem 376 | } 377 | .markdown-section ol, .markdown-section ul { 378 | padding-left: 24px; 379 | padding-left: 1.5rem 380 | } 381 | .markdown-section blockquote { 382 | border-left: 4px solid #42b983; 383 | border-left: 4px solid var(--theme-color, #42b983); 384 | color: #858585; 385 | margin: 2em 0; 386 | padding-left: 20px 387 | } 388 | .markdown-section blockquote p { 389 | font-weight: 600; 390 | margin-left: 0 391 | } 392 | .markdown-section iframe { 393 | margin: 1em 0 394 | } 395 | .markdown-section em { 396 | color: #7f8c8d 397 | } 398 | .markdown-section code { 399 | border-radius: 2px; 400 | color: #e96900; 401 | font-size: 12.8px; 402 | font-size: .8rem; 403 | margin: 0 2px; 404 | padding: 3px 5px; 405 | white-space: pre-wrap 406 | } 407 | .markdown-section code, .markdown-section pre { 408 | background-color: #f8f8f8; 409 | font-family: Roboto Mono, Monaco, courier, monospace 410 | } 411 | .markdown-section pre { 412 | -moz-osx-font-smoothing: initial; 413 | -webkit-font-smoothing: initial; 414 | line-height: 24px; 415 | line-height: 1.5rem; 416 | margin: 1.2em 0; 417 | overflow: auto; 418 | padding: 0 22.4px; 419 | padding: 0 1.4rem; 420 | position: relative; 421 | word-wrap: normal 422 | } 423 | .token.cdata, .token.comment, .token.doctype, .token.prolog { 424 | color: #8e908c 425 | } 426 | .token.namespace { 427 | opacity: .7 428 | } 429 | .token.boolean, .token.number { 430 | color: #c76b29 431 | } 432 | .token.punctuation { 433 | color: #525252 434 | } 435 | .token.property { 436 | color: #c08b30 437 | } 438 | .token.tag { 439 | color: #2973b7 440 | } 441 | .token.string { 442 | color: #42b983; 443 | color: var(--theme-color, #42b983) 444 | } 445 | .token.selector { 446 | color: #6679cc 447 | } 448 | .token.attr-name { 449 | color: #2973b7 450 | } 451 | .language-css .token.string, .style .token.string, .token.entity, .token.url { 452 | color: #22a2c9 453 | } 454 | .token.attr-value, .token.control, .token.directive, .token.unit { 455 | color: #42b983; 456 | color: var(--theme-color, #42b983) 457 | } 458 | .token.keyword { 459 | color: #e96900 460 | } 461 | .token.atrule, .token.regex, .token.statement { 462 | color: #22a2c9 463 | } 464 | .token.placeholder, .token.variable { 465 | color: #3d8fd1 466 | } 467 | .token.deleted { 468 | text-decoration: line-through 469 | } 470 | .token.inserted { 471 | border-bottom: 1px dotted #202746; 472 | text-decoration: none 473 | } 474 | .token.italic { 475 | font-style: italic 476 | } 477 | .token.bold, .token.important { 478 | font-weight: 700 479 | } 480 | .token.important { 481 | color: #c94922 482 | } 483 | .token.entity { 484 | cursor: help 485 | } 486 | .markdown-section pre>code { 487 | -moz-osx-font-smoothing: initial; 488 | -webkit-font-smoothing: initial; 489 | background-color: #f8f8f8; 490 | border-radius: 2px; 491 | color: #525252; 492 | display: block; 493 | font-family: Roboto Mono, Monaco, courier, monospace; 494 | font-size: 12.8px; 495 | font-size: .8rem; 496 | line-height: inherit; 497 | margin: 0 2px; 498 | max-width: inherit; 499 | overflow: inherit; 500 | padding: 2.2em 5px; 501 | white-space: inherit 502 | } 503 | .markdown-section code:after, .markdown-section code:before { 504 | letter-spacing: .8px; 505 | letter-spacing: .05rem 506 | } 507 | code .token { 508 | -moz-osx-font-smoothing: initial; 509 | -webkit-font-smoothing: initial; 510 | min-height: 24px; 511 | min-height: 1.5rem 512 | } 513 | pre:after { 514 | color: #ccc; 515 | content: attr(data-lang); 516 | font-size: 9.6px; 517 | font-size: .6rem; 518 | font-weight: 600; 519 | height: 15px; 520 | line-height: 15px; 521 | padding: 5px 10px 0; 522 | position: absolute; 523 | right: 0; 524 | text-align: right; 525 | top: 0 526 | } -------------------------------------------------------------------------------- /assets/js/highlight.js: -------------------------------------------------------------------------------- 1 | /* 2 | Syntax highlighting with language autodetection. 3 | https://highlightjs.org/ 4 | */ 5 | 6 | (function(factory) { 7 | 8 | // Find the global object for export to both the browser and web workers. 9 | var globalObject = typeof window === 'object' && window || 10 | typeof self === 'object' && self; 11 | 12 | // Setup highlight.js for different environments. First is Node.js or 13 | // CommonJS. 14 | if(typeof exports !== 'undefined') { 15 | factory(exports); 16 | } else if(globalObject) { 17 | // Export hljs globally even when using AMD for cases when this script 18 | // is loaded with others that may still expect a global hljs. 19 | globalObject.hljs = factory({}); 20 | 21 | // Finally register the global hljs with AMD. 22 | if(typeof define === 'function' && define.amd) { 23 | define([], function() { 24 | return globalObject.hljs; 25 | }); 26 | } 27 | } 28 | 29 | }(function(hljs) { 30 | // Convenience variables for build-in objects 31 | var ArrayProto = [], 32 | objectKeys = Object.keys; 33 | 34 | // Global internal variables used within the highlight.js library. 35 | var languages = {}, 36 | aliases = {}; 37 | 38 | // Regular expressions used throughout the highlight.js library. 39 | var noHighlightRe = /^(no-?highlight|plain|text)$/i, 40 | languagePrefixRe = /\blang(?:uage)?-([\w-]+)\b/i, 41 | fixMarkupRe = /((^(<[^>]+>|\t|)+|(?:\n)))/gm; 42 | 43 | var spanEndTag = ''; 44 | 45 | // Global options used when within external APIs. This is modified when 46 | // calling the `hljs.configure` function. 47 | var options = { 48 | classPrefix: 'hljs-', 49 | tabReplace: null, 50 | useBR: false, 51 | languages: undefined 52 | }; 53 | 54 | 55 | /* Utility functions */ 56 | 57 | function escape(value) { 58 | return value.replace(/&/g, '&').replace(//g, '>'); 59 | } 60 | 61 | function tag(node) { 62 | return node.nodeName.toLowerCase(); 63 | } 64 | 65 | function testRe(re, lexeme) { 66 | var match = re && re.exec(lexeme); 67 | return match && match.index === 0; 68 | } 69 | 70 | function isNotHighlighted(language) { 71 | return noHighlightRe.test(language); 72 | } 73 | 74 | function blockLanguage(block) { 75 | var i, match, length, _class; 76 | var classes = block.className + ' '; 77 | 78 | classes += block.parentNode ? block.parentNode.className : ''; 79 | 80 | // language-* takes precedence over non-prefixed class names. 81 | match = languagePrefixRe.exec(classes); 82 | if (match) { 83 | return getLanguage(match[1]) ? match[1] : 'no-highlight'; 84 | } 85 | 86 | classes = classes.split(/\s+/); 87 | 88 | for (i = 0, length = classes.length; i < length; i++) { 89 | _class = classes[i] 90 | 91 | if (isNotHighlighted(_class) || getLanguage(_class)) { 92 | return _class; 93 | } 94 | } 95 | } 96 | 97 | function inherit(parent) { // inherit(parent, override_obj, override_obj, ...) 98 | var key; 99 | var result = {}; 100 | var objects = Array.prototype.slice.call(arguments, 1); 101 | 102 | for (key in parent) 103 | result[key] = parent[key]; 104 | objects.forEach(function(obj) { 105 | for (key in obj) 106 | result[key] = obj[key]; 107 | }); 108 | return result; 109 | } 110 | 111 | /* Stream merging */ 112 | 113 | function nodeStream(node) { 114 | var result = []; 115 | (function _nodeStream(node, offset) { 116 | for (var child = node.firstChild; child; child = child.nextSibling) { 117 | if (child.nodeType === 3) 118 | offset += child.nodeValue.length; 119 | else if (child.nodeType === 1) { 120 | result.push({ 121 | event: 'start', 122 | offset: offset, 123 | node: child 124 | }); 125 | offset = _nodeStream(child, offset); 126 | // Prevent void elements from having an end tag that would actually 127 | // double them in the output. There are more void elements in HTML 128 | // but we list only those realistically expected in code display. 129 | if (!tag(child).match(/br|hr|img|input/)) { 130 | result.push({ 131 | event: 'stop', 132 | offset: offset, 133 | node: child 134 | }); 135 | } 136 | } 137 | } 138 | return offset; 139 | })(node, 0); 140 | return result; 141 | } 142 | 143 | function mergeStreams(original, highlighted, value) { 144 | var processed = 0; 145 | var result = ''; 146 | var nodeStack = []; 147 | 148 | function selectStream() { 149 | if (!original.length || !highlighted.length) { 150 | return original.length ? original : highlighted; 151 | } 152 | if (original[0].offset !== highlighted[0].offset) { 153 | return (original[0].offset < highlighted[0].offset) ? original : highlighted; 154 | } 155 | 156 | /* 157 | To avoid starting the stream just before it should stop the order is 158 | ensured that original always starts first and closes last: 159 | 160 | if (event1 == 'start' && event2 == 'start') 161 | return original; 162 | if (event1 == 'start' && event2 == 'stop') 163 | return highlighted; 164 | if (event1 == 'stop' && event2 == 'start') 165 | return original; 166 | if (event1 == 'stop' && event2 == 'stop') 167 | return highlighted; 168 | 169 | ... which is collapsed to: 170 | */ 171 | return highlighted[0].event === 'start' ? original : highlighted; 172 | } 173 | 174 | function open(node) { 175 | function attr_str(a) {return ' ' + a.nodeName + '="' + escape(a.value).replace('"', '"') + '"';} 176 | result += '<' + tag(node) + ArrayProto.map.call(node.attributes, attr_str).join('') + '>'; 177 | } 178 | 179 | function close(node) { 180 | result += ''; 181 | } 182 | 183 | function render(event) { 184 | (event.event === 'start' ? open : close)(event.node); 185 | } 186 | 187 | while (original.length || highlighted.length) { 188 | var stream = selectStream(); 189 | result += escape(value.substring(processed, stream[0].offset)); 190 | processed = stream[0].offset; 191 | if (stream === original) { 192 | /* 193 | On any opening or closing tag of the original markup we first close 194 | the entire highlighted node stack, then render the original tag along 195 | with all the following original tags at the same offset and then 196 | reopen all the tags on the highlighted stack. 197 | */ 198 | nodeStack.reverse().forEach(close); 199 | do { 200 | render(stream.splice(0, 1)[0]); 201 | stream = selectStream(); 202 | } while (stream === original && stream.length && stream[0].offset === processed); 203 | nodeStack.reverse().forEach(open); 204 | } else { 205 | if (stream[0].event === 'start') { 206 | nodeStack.push(stream[0].node); 207 | } else { 208 | nodeStack.pop(); 209 | } 210 | render(stream.splice(0, 1)[0]); 211 | } 212 | } 213 | return result + escape(value.substr(processed)); 214 | } 215 | 216 | /* Initialization */ 217 | 218 | function expand_mode(mode) { 219 | if (mode.variants && !mode.cached_variants) { 220 | mode.cached_variants = mode.variants.map(function(variant) { 221 | return inherit(mode, {variants: null}, variant); 222 | }); 223 | } 224 | return mode.cached_variants || (mode.endsWithParent && [inherit(mode)]) || [mode]; 225 | } 226 | 227 | function compileLanguage(language) { 228 | 229 | function reStr(re) { 230 | return (re && re.source) || re; 231 | } 232 | 233 | function langRe(value, global) { 234 | return new RegExp( 235 | reStr(value), 236 | 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '') 237 | ); 238 | } 239 | 240 | function compileMode(mode, parent) { 241 | if (mode.compiled) 242 | return; 243 | mode.compiled = true; 244 | 245 | mode.keywords = mode.keywords || mode.beginKeywords; 246 | if (mode.keywords) { 247 | var compiled_keywords = {}; 248 | 249 | var flatten = function(className, str) { 250 | if (language.case_insensitive) { 251 | str = str.toLowerCase(); 252 | } 253 | str.split(' ').forEach(function(kw) { 254 | var pair = kw.split('|'); 255 | compiled_keywords[pair[0]] = [className, pair[1] ? Number(pair[1]) : 1]; 256 | }); 257 | }; 258 | 259 | if (typeof mode.keywords === 'string') { // string 260 | flatten('keyword', mode.keywords); 261 | } else { 262 | objectKeys(mode.keywords).forEach(function (className) { 263 | flatten(className, mode.keywords[className]); 264 | }); 265 | } 266 | mode.keywords = compiled_keywords; 267 | } 268 | mode.lexemesRe = langRe(mode.lexemes || /\w+/, true); 269 | 270 | if (parent) { 271 | if (mode.beginKeywords) { 272 | mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')\\b'; 273 | } 274 | if (!mode.begin) 275 | mode.begin = /\B|\b/; 276 | mode.beginRe = langRe(mode.begin); 277 | if (!mode.end && !mode.endsWithParent) 278 | mode.end = /\B|\b/; 279 | if (mode.end) 280 | mode.endRe = langRe(mode.end); 281 | mode.terminator_end = reStr(mode.end) || ''; 282 | if (mode.endsWithParent && parent.terminator_end) 283 | mode.terminator_end += (mode.end ? '|' : '') + parent.terminator_end; 284 | } 285 | if (mode.illegal) 286 | mode.illegalRe = langRe(mode.illegal); 287 | if (mode.relevance == null) 288 | mode.relevance = 1; 289 | if (!mode.contains) { 290 | mode.contains = []; 291 | } 292 | mode.contains = Array.prototype.concat.apply([], mode.contains.map(function(c) { 293 | return expand_mode(c === 'self' ? mode : c) 294 | })); 295 | mode.contains.forEach(function(c) {compileMode(c, mode);}); 296 | 297 | if (mode.starts) { 298 | compileMode(mode.starts, parent); 299 | } 300 | 301 | var terminators = 302 | mode.contains.map(function(c) { 303 | return c.beginKeywords ? '\\.?(' + c.begin + ')\\.?' : c.begin; 304 | }) 305 | .concat([mode.terminator_end, mode.illegal]) 306 | .map(reStr) 307 | .filter(Boolean); 308 | mode.terminators = terminators.length ? langRe(terminators.join('|'), true) : {exec: function(/*s*/) {return null;}}; 309 | } 310 | 311 | compileMode(language); 312 | } 313 | 314 | /* 315 | Core highlighting function. Accepts a language name, or an alias, and a 316 | string with the code to highlight. Returns an object with the following 317 | properties: 318 | 319 | - relevance (int) 320 | - value (an HTML string with highlighting markup) 321 | 322 | */ 323 | function highlight(name, value, ignore_illegals, continuation) { 324 | 325 | function subMode(lexeme, mode) { 326 | var i, length; 327 | 328 | for (i = 0, length = mode.contains.length; i < length; i++) { 329 | if (testRe(mode.contains[i].beginRe, lexeme)) { 330 | return mode.contains[i]; 331 | } 332 | } 333 | } 334 | 335 | function endOfMode(mode, lexeme) { 336 | if (testRe(mode.endRe, lexeme)) { 337 | while (mode.endsParent && mode.parent) { 338 | mode = mode.parent; 339 | } 340 | return mode; 341 | } 342 | if (mode.endsWithParent) { 343 | return endOfMode(mode.parent, lexeme); 344 | } 345 | } 346 | 347 | function isIllegal(lexeme, mode) { 348 | return !ignore_illegals && testRe(mode.illegalRe, lexeme); 349 | } 350 | 351 | function keywordMatch(mode, match) { 352 | var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0]; 353 | return mode.keywords.hasOwnProperty(match_str) && mode.keywords[match_str]; 354 | } 355 | 356 | function buildSpan(classname, insideSpan, leaveOpen, noPrefix) { 357 | var classPrefix = noPrefix ? '' : options.classPrefix, 358 | openSpan = ''; 362 | 363 | return openSpan + insideSpan + closeSpan; 364 | } 365 | 366 | function processKeywords() { 367 | var keyword_match, last_index, match, result; 368 | 369 | if (!top.keywords) 370 | return escape(mode_buffer); 371 | 372 | result = ''; 373 | last_index = 0; 374 | top.lexemesRe.lastIndex = 0; 375 | match = top.lexemesRe.exec(mode_buffer); 376 | 377 | while (match) { 378 | result += escape(mode_buffer.substring(last_index, match.index)); 379 | keyword_match = keywordMatch(top, match); 380 | if (keyword_match) { 381 | relevance += keyword_match[1]; 382 | result += buildSpan(keyword_match[0], escape(match[0])); 383 | } else { 384 | result += escape(match[0]); 385 | } 386 | last_index = top.lexemesRe.lastIndex; 387 | match = top.lexemesRe.exec(mode_buffer); 388 | } 389 | return result + escape(mode_buffer.substr(last_index)); 390 | } 391 | 392 | function processSubLanguage() { 393 | var explicit = typeof top.subLanguage === 'string'; 394 | if (explicit && !languages[top.subLanguage]) { 395 | return escape(mode_buffer); 396 | } 397 | 398 | var result = explicit ? 399 | highlight(top.subLanguage, mode_buffer, true, continuations[top.subLanguage]) : 400 | highlightAuto(mode_buffer, top.subLanguage.length ? top.subLanguage : undefined); 401 | 402 | // Counting embedded language score towards the host language may be disabled 403 | // with zeroing the containing mode relevance. Usecase in point is Markdown that 404 | // allows XML everywhere and makes every XML snippet to have a much larger Markdown 405 | // score. 406 | if (top.relevance > 0) { 407 | relevance += result.relevance; 408 | } 409 | if (explicit) { 410 | continuations[top.subLanguage] = result.top; 411 | } 412 | return buildSpan(result.language, result.value, false, true); 413 | } 414 | 415 | function processBuffer() { 416 | result += (top.subLanguage != null ? processSubLanguage() : processKeywords()); 417 | mode_buffer = ''; 418 | } 419 | 420 | function startNewMode(mode) { 421 | result += mode.className? buildSpan(mode.className, '', true): ''; 422 | top = Object.create(mode, {parent: {value: top}}); 423 | } 424 | 425 | function processLexeme(buffer, lexeme) { 426 | 427 | mode_buffer += buffer; 428 | 429 | if (lexeme == null) { 430 | processBuffer(); 431 | return 0; 432 | } 433 | 434 | var new_mode = subMode(lexeme, top); 435 | if (new_mode) { 436 | if (new_mode.skip) { 437 | mode_buffer += lexeme; 438 | } else { 439 | if (new_mode.excludeBegin) { 440 | mode_buffer += lexeme; 441 | } 442 | processBuffer(); 443 | if (!new_mode.returnBegin && !new_mode.excludeBegin) { 444 | mode_buffer = lexeme; 445 | } 446 | } 447 | startNewMode(new_mode, lexeme); 448 | return new_mode.returnBegin ? 0 : lexeme.length; 449 | } 450 | 451 | var end_mode = endOfMode(top, lexeme); 452 | if (end_mode) { 453 | var origin = top; 454 | if (origin.skip) { 455 | mode_buffer += lexeme; 456 | } else { 457 | if (!(origin.returnEnd || origin.excludeEnd)) { 458 | mode_buffer += lexeme; 459 | } 460 | processBuffer(); 461 | if (origin.excludeEnd) { 462 | mode_buffer = lexeme; 463 | } 464 | } 465 | do { 466 | if (top.className) { 467 | result += spanEndTag; 468 | } 469 | if (!top.skip && !top.subLanguage) { 470 | relevance += top.relevance; 471 | } 472 | top = top.parent; 473 | } while (top !== end_mode.parent); 474 | if (end_mode.starts) { 475 | startNewMode(end_mode.starts, ''); 476 | } 477 | return origin.returnEnd ? 0 : lexeme.length; 478 | } 479 | 480 | if (isIllegal(lexeme, top)) 481 | throw new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.className || '') + '"'); 482 | 483 | /* 484 | Parser should not reach this point as all types of lexemes should be caught 485 | earlier, but if it does due to some bug make sure it advances at least one 486 | character forward to prevent infinite looping. 487 | */ 488 | mode_buffer += lexeme; 489 | return lexeme.length || 1; 490 | } 491 | 492 | var language = getLanguage(name); 493 | if (!language) { 494 | throw new Error('Unknown language: "' + name + '"'); 495 | } 496 | 497 | compileLanguage(language); 498 | var top = continuation || language; 499 | var continuations = {}; // keep continuations for sub-languages 500 | var result = '', current; 501 | for(current = top; current !== language; current = current.parent) { 502 | if (current.className) { 503 | result = buildSpan(current.className, '', true) + result; 504 | } 505 | } 506 | var mode_buffer = ''; 507 | var relevance = 0; 508 | try { 509 | var match, count, index = 0; 510 | while (true) { 511 | top.terminators.lastIndex = index; 512 | match = top.terminators.exec(value); 513 | if (!match) 514 | break; 515 | count = processLexeme(value.substring(index, match.index), match[0]); 516 | index = match.index + count; 517 | } 518 | processLexeme(value.substr(index)); 519 | for(current = top; current.parent; current = current.parent) { // close dangling modes 520 | if (current.className) { 521 | result += spanEndTag; 522 | } 523 | } 524 | return { 525 | relevance: relevance, 526 | value: result, 527 | language: name, 528 | top: top 529 | }; 530 | } catch (e) { 531 | if (e.message && e.message.indexOf('Illegal') !== -1) { 532 | return { 533 | relevance: 0, 534 | value: escape(value) 535 | }; 536 | } else { 537 | throw e; 538 | } 539 | } 540 | } 541 | 542 | /* 543 | Highlighting with language detection. Accepts a string with the code to 544 | highlight. Returns an object with the following properties: 545 | 546 | - language (detected language) 547 | - relevance (int) 548 | - value (an HTML string with highlighting markup) 549 | - second_best (object with the same structure for second-best heuristically 550 | detected language, may be absent) 551 | 552 | */ 553 | function highlightAuto(text, languageSubset) { 554 | languageSubset = languageSubset || options.languages || objectKeys(languages); 555 | var result = { 556 | relevance: 0, 557 | value: escape(text) 558 | }; 559 | var second_best = result; 560 | languageSubset.filter(getLanguage).forEach(function(name) { 561 | var current = highlight(name, text, false); 562 | current.language = name; 563 | if (current.relevance > second_best.relevance) { 564 | second_best = current; 565 | } 566 | if (current.relevance > result.relevance) { 567 | second_best = result; 568 | result = current; 569 | } 570 | }); 571 | if (second_best.language) { 572 | result.second_best = second_best; 573 | } 574 | return result; 575 | } 576 | 577 | /* 578 | Post-processing of the highlighted markup: 579 | 580 | - replace TABs with something more useful 581 | - replace real line-breaks with '
' for non-pre containers 582 | 583 | */ 584 | function fixMarkup(value) { 585 | return !(options.tabReplace || options.useBR) 586 | ? value 587 | : value.replace(fixMarkupRe, function(match, p1) { 588 | if (options.useBR && match === '\n') { 589 | return '
'; 590 | } else if (options.tabReplace) { 591 | return p1.replace(/\t/g, options.tabReplace); 592 | } 593 | return ''; 594 | }); 595 | } 596 | 597 | function buildClassName(prevClassName, currentLang, resultLang) { 598 | var language = currentLang ? aliases[currentLang] : resultLang, 599 | result = [prevClassName.trim()]; 600 | 601 | if (!prevClassName.match(/\bhljs\b/)) { 602 | result.push('hljs'); 603 | } 604 | 605 | if (prevClassName.indexOf(language) === -1) { 606 | result.push(language); 607 | } 608 | 609 | return result.join(' ').trim(); 610 | } 611 | 612 | /* 613 | Applies highlighting to a DOM node containing code. Accepts a DOM node and 614 | two optional parameters for fixMarkup. 615 | */ 616 | function highlightBlock(block) { 617 | var node, originalStream, result, resultNode, text; 618 | var language = blockLanguage(block); 619 | 620 | if (isNotHighlighted(language)) 621 | return; 622 | 623 | if (options.useBR) { 624 | node = document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); 625 | node.innerHTML = block.innerHTML.replace(/\n/g, '').replace(//g, '\n'); 626 | } else { 627 | node = block; 628 | } 629 | text = node.textContent; 630 | result = language ? highlight(language, text, true) : highlightAuto(text); 631 | 632 | originalStream = nodeStream(node); 633 | if (originalStream.length) { 634 | resultNode = document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); 635 | resultNode.innerHTML = result.value; 636 | result.value = mergeStreams(originalStream, nodeStream(resultNode), text); 637 | } 638 | result.value = fixMarkup(result.value); 639 | 640 | block.innerHTML = result.value; 641 | // block.parent.setAttribute("data-lang",language); 642 | block.className = buildClassName(block.className, language, result.language); 643 | block.result = { 644 | language: result.language, 645 | re: result.relevance 646 | }; 647 | if (result.second_best) { 648 | block.second_best = { 649 | language: result.second_best.language, 650 | re: result.second_best.relevance 651 | }; 652 | } 653 | } 654 | 655 | /* 656 | Updates highlight.js global options with values passed in the form of an object. 657 | */ 658 | function configure(user_options) { 659 | options = inherit(options, user_options); 660 | } 661 | 662 | /* 663 | Applies highlighting to all
..
blocks on a page. 664 | */ 665 | function initHighlighting() { 666 | if (initHighlighting.called) 667 | return; 668 | initHighlighting.called = true; 669 | 670 | var blocks = document.querySelectorAll('pre code'); 671 | ArrayProto.forEach.call(blocks, highlightBlock); 672 | } 673 | 674 | /* 675 | Attaches highlighting to the page load event. 676 | */ 677 | function initHighlightingOnLoad() { 678 | addEventListener('DOMContentLoaded', initHighlighting, false); 679 | addEventListener('load', initHighlighting, false); 680 | } 681 | 682 | function registerLanguage(name, language) { 683 | var lang = languages[name] = language(hljs); 684 | if (lang.aliases) { 685 | lang.aliases.forEach(function(alias) {aliases[alias] = name;}); 686 | } 687 | } 688 | 689 | function listLanguages() { 690 | return objectKeys(languages); 691 | } 692 | 693 | function getLanguage(name) { 694 | name = (name || '').toLowerCase(); 695 | return languages[name] || languages[aliases[name]]; 696 | } 697 | 698 | /* Interface definition */ 699 | 700 | hljs.highlight = highlight; 701 | hljs.highlightAuto = highlightAuto; 702 | hljs.fixMarkup = fixMarkup; 703 | hljs.highlightBlock = highlightBlock; 704 | hljs.configure = configure; 705 | hljs.initHighlighting = initHighlighting; 706 | hljs.initHighlightingOnLoad = initHighlightingOnLoad; 707 | hljs.registerLanguage = registerLanguage; 708 | hljs.listLanguages = listLanguages; 709 | hljs.getLanguage = getLanguage; 710 | hljs.inherit = inherit; 711 | 712 | // Common regexps 713 | hljs.IDENT_RE = '[a-zA-Z]\\w*'; 714 | hljs.UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*'; 715 | hljs.NUMBER_RE = '\\b\\d+(\\.\\d+)?'; 716 | hljs.C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float 717 | hljs.BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b... 718 | hljs.RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; 719 | 720 | // Common modes 721 | hljs.BACKSLASH_ESCAPE = { 722 | begin: '\\\\[\\s\\S]', relevance: 0 723 | }; 724 | hljs.APOS_STRING_MODE = { 725 | className: 'string', 726 | begin: '\'', end: '\'', 727 | illegal: '\\n', 728 | contains: [hljs.BACKSLASH_ESCAPE] 729 | }; 730 | hljs.QUOTE_STRING_MODE = { 731 | className: 'string', 732 | begin: '"', end: '"', 733 | illegal: '\\n', 734 | contains: [hljs.BACKSLASH_ESCAPE] 735 | }; 736 | hljs.PHRASAL_WORDS_MODE = { 737 | begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ 738 | }; 739 | hljs.COMMENT = function (begin, end, inherits) { 740 | var mode = hljs.inherit( 741 | { 742 | className: 'comment', 743 | begin: begin, end: end, 744 | contains: [] 745 | }, 746 | inherits || {} 747 | ); 748 | mode.contains.push(hljs.PHRASAL_WORDS_MODE); 749 | mode.contains.push({ 750 | className: 'doctag', 751 | begin: '(?:TODO|FIXME|NOTE|BUG|XXX):', 752 | relevance: 0 753 | }); 754 | return mode; 755 | }; 756 | hljs.C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$'); 757 | hljs.C_BLOCK_COMMENT_MODE = hljs.COMMENT('/\\*', '\\*/'); 758 | hljs.HASH_COMMENT_MODE = hljs.COMMENT('#', '$'); 759 | hljs.NUMBER_MODE = { 760 | className: 'number', 761 | begin: hljs.NUMBER_RE, 762 | relevance: 0 763 | }; 764 | hljs.C_NUMBER_MODE = { 765 | className: 'number', 766 | begin: hljs.C_NUMBER_RE, 767 | relevance: 0 768 | }; 769 | hljs.BINARY_NUMBER_MODE = { 770 | className: 'number', 771 | begin: hljs.BINARY_NUMBER_RE, 772 | relevance: 0 773 | }; 774 | hljs.CSS_NUMBER_MODE = { 775 | className: 'number', 776 | begin: hljs.NUMBER_RE + '(' + 777 | '%|em|ex|ch|rem' + 778 | '|vw|vh|vmin|vmax' + 779 | '|cm|mm|in|pt|pc|px' + 780 | '|deg|grad|rad|turn' + 781 | '|s|ms' + 782 | '|Hz|kHz' + 783 | '|dpi|dpcm|dppx' + 784 | ')?', 785 | relevance: 0 786 | }; 787 | hljs.REGEXP_MODE = { 788 | className: 'regexp', 789 | begin: /\//, end: /\/[gimuy]*/, 790 | illegal: /\n/, 791 | contains: [ 792 | hljs.BACKSLASH_ESCAPE, 793 | { 794 | begin: /\[/, end: /\]/, 795 | relevance: 0, 796 | contains: [hljs.BACKSLASH_ESCAPE] 797 | } 798 | ] 799 | }; 800 | hljs.TITLE_MODE = { 801 | className: 'title', 802 | begin: hljs.IDENT_RE, 803 | relevance: 0 804 | }; 805 | hljs.UNDERSCORE_TITLE_MODE = { 806 | className: 'title', 807 | begin: hljs.UNDERSCORE_IDENT_RE, 808 | relevance: 0 809 | }; 810 | hljs.METHOD_GUARD = { 811 | // excludes method names from keyword processing 812 | begin: '\\.\\s*' + hljs.UNDERSCORE_IDENT_RE, 813 | relevance: 0 814 | }; 815 | 816 | return hljs; 817 | })); 818 | -------------------------------------------------------------------------------- /assets/js/index.js: -------------------------------------------------------------------------------- 1 | var tags = document.querySelectorAll('.tag-box') 2 | for (var i = 0, len = tags.length; i < len; i++) { 3 | var tag = tags[i] 4 | if(!tag){ 5 | continue; 6 | } 7 | var childNodes = tag.childNodes 8 | for (var x = 0, len2 = childNodes.length; x < len2; x++) { 9 | var node = childNodes[x] 10 | if (node&&node.nodeType == 3) { 11 | tags[i].removeChild(node) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /assets/js/post.js: -------------------------------------------------------------------------------- 1 | hljs.configure({ 2 | tabReplace: ' ', 3 | classPrefix: '' 4 | }) 5 | hljs.initHighlightingOnLoad() 6 | var links=document.querySelectorAll('.post a'); 7 | for (var i = links.length - 1; i >= 0; i--) { 8 | links[i].setAttribute('target','_blank') 9 | } -------------------------------------------------------------------------------- /assets/screenshot-desktop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaohaodang/ghost-theme-tiny/68bc19a4c7663cf0b9ab46988ea049c6912267cc/assets/screenshot-desktop.jpg -------------------------------------------------------------------------------- /assets/screenshot-mobile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaohaodang/ghost-theme-tiny/68bc19a4c7663cf0b9ab46988ea049c6912267cc/assets/screenshot-mobile.jpg -------------------------------------------------------------------------------- /custom-archives.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} {{> "header"}} 2 | {{#post}} 3 |
4 |
5 |
6 |
7 |

8 | {{! count posts }} {{#get "posts" as |posts postPages|}} {{! Use our pages (pagination) object 9 | }} 10 | 目前共计  11 | {{postPages.total}} 篇日志,继续努力! 12 | {{/get}} 13 |

14 | {{#get "posts" limit="all" order="published_at desc"}} {{#foreach posts}} 15 |
16 |
17 | 19 | {{title}} 20 |
21 |
22 | {{/foreach}} {{/get}} 23 |
24 |
25 |
26 |
27 | 28 | {{/post}} 29 | -------------------------------------------------------------------------------- /custom-tags.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} {{> "header"}} 2 | {{#post}} 3 | 4 |
5 |
6 | {{#get 'tags' limit='all' include='count.posts' order='count.posts desc'}} 7 | 目前共计  8 | {{tags.length}} 个标签,继续努力! 9 | 10 |
11 | {{#foreach tags}} 12 | 13 | {{ name }} ({{ count.posts }}) 14 | 15 | {{/foreach}} 16 |
17 | {{/get}} 18 |
19 |
20 | 21 | {{/post}} -------------------------------------------------------------------------------- /default.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{!-- Document Settings --}} 5 | 6 | 7 | 8 | {{!-- Page Meta --}} 9 | {{meta_title}} 10 | 11 | {{!-- Mobile Meta --}} 12 | 13 | 14 | 15 | {{!-- Brand icon --}} 16 | 17 | 18 | {{!-- Styles'n'Scripts --}} 19 | 20 | 21 | 22 | 23 | 24 | {{!-- {{#is "index"}}{{/is}} --}} 25 | 26 | {{#is "post"}} 27 | {{!-- --}} 28 | 29 | {{/is}} 30 | {{!-- {{#is "archives"}}{{/is}} --}} 31 | {{!-- Ghost outputs important style and meta data with this tag --}} 32 | {{ghost_head}} 33 | 34 | 35 | 36 |
37 | {{!-- All the main content gets inserted here, index.hbs, post.hbs, etc --}} 38 | {{{body}}} 39 |
40 | 41 | {{!-- jQuery needs to come before `{{ghost_foot}}` so that jQuery can be used in code injection --}} 42 | {{!----}} 43 | {{!-- Ghost outputs important scripts and data with this tag --}} 44 | {{ghost_foot}} 45 | {{!-- The main JavaScript file for Casper --}} 46 | 47 | {{#is "post"}} 48 | 49 | 50 | {{/is}} 51 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /index.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | {{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}} 3 | {{> "header"}} 4 | {{!-- The main content area on the homepage --}} 5 |
6 | {{!-- The tag below includes the post loop - partials/loop.hbs --}} {{> "loop"}} 7 |
-------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ghost-theme-tiny", 3 | "description": "A tiny personal blogging theme for Ghost. Beautiful, minimal and responsive.", 4 | "demo": "https://demo.ghost.io", 5 | "version": "1.1.3", 6 | "engines": { 7 | "ghost": ">=1.0.0", 8 | "ghost-api": "v4" 9 | }, 10 | "license": "MIT", 11 | "screenshots": { 12 | "desktop": "assets/screenshot-desktop.jpg", 13 | "mobile": "assets/screenshot-mobile.jpg" 14 | }, 15 | "config": { 16 | "posts_per_page": 10 17 | }, 18 | "author": { 19 | "name": "zhaohaodang", 20 | "email": "zhaohaodang@gmail.com", 21 | "url": "https://zhaohaodang.com" 22 | }, 23 | "gpm": { 24 | "type": "theme", 25 | "categories": [ 26 | "Minimal", 27 | "Personal Blogs" 28 | ] 29 | }, 30 | "keywords": [ 31 | "ghost", 32 | "theme", 33 | "ghost-theme" 34 | ], 35 | "repository": { 36 | "type": "git", 37 | "url": "https://github.com/zhaohaodang/ghost-theme-tiny.git" 38 | }, 39 | "bugs": "https://github.com/zhaohaodang/ghost-theme-tiny/issues", 40 | "contributors": "https://github.com/zhaohaodang/ghost-theme-tiny/graphs/contributors" 41 | } 42 | -------------------------------------------------------------------------------- /page-archives.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | {{> "header"}} {{! This is a page template. A page outputs content just like any other post, and has all the same attributes 3 | by default, but you can also customise it to behave differently if you prefer. }} {{! Everything inside the #post tags 4 | pulls data from the page }} {{#post}} {{! The main container area on the homepage }} 5 |
6 |
7 |
8 |
9 |

10 | {{! count posts }} {{#get "posts" as |posts postPages|}} {{! Use our pages (pagination) object }} 11 | 目前共计  12 | {{postPages.total}} 篇日志,继续努力! 13 | {{/get}} 14 |

15 | {{#get "posts" limit="all" order="published_at desc"}} {{#foreach posts}} 16 |
17 |
18 | 19 | {{title}} 20 |
21 |
22 | {{/foreach}} {{/get}} 23 |
24 |
25 |
26 |
27 | 28 | {{/post}} 29 | -------------------------------------------------------------------------------- /partials/header.hbs: -------------------------------------------------------------------------------- 1 | {{#if @site.navigation}} {{navigation}}{{/if}} 2 |
3 | {{#if @site.logo}} 4 | 5 | {{/if}} 6 | {{@site.title}} 7 |
8 | -------------------------------------------------------------------------------- /partials/loop.hbs: -------------------------------------------------------------------------------- 1 | {{!-- This is the post loop - each post will be output using this markup --}} 2 |
    3 | {{#foreach posts}} 4 |
  • 5 |

    {{date format="YYYY MM/DD"}}

    6 |

    7 | {{title}} 8 |

    9 | {{tags}} 10 |

    11 |

    12 |
  • 13 | {{/foreach}} 14 |
15 | {{!-- Previous/next page links - displayed on every page --}} 16 | {{pagination}} 17 | -------------------------------------------------------------------------------- /partials/navigation.hbs: -------------------------------------------------------------------------------- 1 | {{! navigation }} 2 | -------------------------------------------------------------------------------- /partials/pagination.hbs: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /post.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} {{> "header"}} 2 | {{!-- The comment above " 3 | < default " means - insert everything in this file into 4 | the {{{body}}} of the default.hbs template, containing the blog header/footer. --}} 5 | 6 | {{!-- Everything inside the #post tags pulls data from the post --}} 7 | {{#post}} 8 |
9 |
10 |

{{date format="YYYY-DD-MM "}}

11 |

{{title}}

12 |
13 | {{content}} 14 |
15 |
16 | 17 | {{!-- Links to Previous/Next posts --}} 18 | 30 |
31 |
32 | {{/post}} 33 | --------------------------------------------------------------------------------