├── .DS_Store ├── .gitattributes ├── .gitignore ├── 404.php ├── CHANGELOG.md ├── LICENSE ├── README.md ├── assets ├── .DS_Store ├── css │ ├── .DS_Store │ ├── comments.css │ └── styles.css ├── img │ └── hero-bg.jpg └── js │ ├── .DS_Store │ ├── bundle.js │ ├── commentAjax.js │ └── pjax.js ├── comments.php ├── footer.php ├── full-width-for-post.php ├── functions.php ├── header.php ├── index.php ├── lib ├── Comments.php └── Utils.php ├── page-about.php ├── page-archive.php ├── page-links.php ├── page.php ├── post.php ├── screenshot.png └── search.php /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unsafe-ptr/Spring/23d1f9522acf20328441432340609cef3cc74082/.DS_Store -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /404.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | <?php $this->archiveTitle(array( 10 | 'category' => _t('%s'), 11 | 'search' => _t('%s'), 12 | 'tag' => _t('%s'), 13 | 'author' => _t('%s') 14 | ), '', ' - '); ?><?php $this->options->title(); ?><?php if ($this->is('index') && $this->options->Subtitle != null) { 15 | echo ' - ' . $this->options->Subtitle; 16 | } ?> 17 | 18 | options->qiniu)): ?> 19 | 20 | 21 | options->logoUrl): ?> 22 | 23 | 24 | 25 | 27 | 28 | is('post')): ?> 29 | 30 | 31 | options->Logo != null): ?> 32 | 33 | 34 | header(); ?> 35 | is('post')): ?> 36 | 37 | 38 | 39 |
40 |
41 |
42 |
43 |

Error 404

44 |

Page not found

45 | 返回首页 46 |
47 |
48 |
49 |
50 | 67 | 68 | 69 | 70 |
71 |
72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | 88 | 89 | footer(); ?> 90 | 91 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### Version 1.0.10 2 | - 修复一些奇怪的问题 3 | ### Version 1.0.9 4 | - ❤️ 修复移动端表格错位 5 | - ❤️ 升级 Valine 6 | ### Version 1.0.8 7 | - ❤️ 更新依赖 8 | - ❤️ 文章页样式微调 9 | - ❤️ 移除首页滚动效果动画 10 | ### Version 1.0.7 11 | - 🎁 新增文章标签新标签打开 12 | - 🎁 新增文章事项清单可视化 13 | - 🎁 新增页脚展示功能 14 | - ❤ 优化首页文章布局 15 | ### Version 1.0.6 16 | - ❤ 优化各种细节 17 | - ❤ 添加AJAX评论 18 | ### Version 1.0.5 19 | - ❤ 优化文章图片显示 20 | - ❤ 重写关于模板 21 | - ❤ 优化 css 兼容 22 | - ❤ 优化部分标签显示间距 23 | - 🎁 重写首页头部模板,作者模板作为重点个人介绍,而不是首页 24 | ### Version 1.0.4 25 | - ✔ 修复移动端搜索遮罩层丢失的问题 26 | - ❤ 优化文章分享 27 | - ❤ 优化文章目录 28 | - ❤ 优化移动端首页波浪显示 29 | - ❤ 优化首页文章间距 30 | - ❤ 优化独立页面和文章页面区分显示 31 | - 🎁 新增标签分类独立页展示 32 | - 🎁 新增图片放大支持 33 | - 🎁 新增友链页面展示 34 | ### Version 1.0.3 35 | 发布日期:2020.02.11 36 | 37 | - ✔ 修复移动端 Ghost 书签错位的问题 38 | - 👀 增强 `文章代码` 阅读性 39 | - ❤ 优化 `文章代码` 样式 40 | - ❤ 优化黑暗模式细节样式 41 | - ❤ 优化网站 LOGO 颜色显示 42 | - 🎁 新增文章目录 43 | - 🎁 新增切换黑暗模式提示 44 | - 🎁 新增部分网站特效 45 | - 🎁 新增文章分享 46 | - 🎁 分类目录背景自定义 47 | ### Version 1.0.3 48 | 发布日期:2020.02.07 49 | 50 | - 修复移动端文章超链接过长导致错位的问题 51 | - 修复黑暗模式下导航顶部不透明的问他 52 | - 修复书签字体大小错位的问题 53 | - 优化黑暗模式显示 54 | - 优化文章标题显示 55 | - 优化文章摘要显示 56 | - 优化系统级黑暗模式删除切换风格按钮(原生黑暗无法切换主题风格) 57 | - 替换语法高亮为 `Prism.js` 类库 58 | - 增强 `js` 渲染引擎兼容性 59 | ### Version 1.0.0 60 | 发布日期:2020.02.03 61 | 62 | - 优化移动端关闭侧边栏操作 63 | - 禁止移动端网页缩放显示 64 | - 修复黑暗模式中文章列表错位的问题 65 | - 更新网页动画展示 66 | ### Version 1.0.0 67 | 发布日期:2020.02.02 68 | 69 | - 优化响应式布局展示 70 | - 支持手动切换主题风格模式 71 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Plug-in unit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TYPECHO Theme - Spring 2 | ### PJAX版本 3 | [TYPECHO THEME PJAX](https://github.com/JaydenForYou/Spring/tree/typecho-theme-pjax) 4 | ### 特色 5 | - 大气、简约、优雅以及强大的响应式布局 6 | - 原生黑暗模式,支持 macOS 和 window10 黑暗模式 7 | - 俩种风格文章模板,全宽和含有文章目录的模板 8 | - 友情链接和关于独立页独特模板,更好展示自己站点 9 | - 恰到好处的个人社交信息 10 | - 适合于中文字体阅读个人文章页面,优化到每一个元素 11 | - Valine 评论系统的支持 12 | - 强大的社交分享文章功能 13 | - 增强模板 SEO 优化 14 | - ...更多功能等你来体验 15 | 16 | ## 更新日志 17 | [参考 CHANGELOG](./CHANGELOG.md) 18 | 19 | ## 使用指南 20 | * 请把主题文件名改为Spring 21 | * 本主题与EditorMD插件冲突,无需使用EditorMD,主题自带解析 22 | ## 为了突出个人介绍 23 | 请在后台点击自己的个人资料->个人主页地址栏填写如下规则以便后端完成解析(格式一定要对,否则出错) 24 | > 个人主页地址$签名$物理地址(如广东 广州) 25 | ## 如何自定义分类目录背景 26 | 在该分类下的分类描述填入如下内容: 27 | > 分类描述$背景图片地址 28 | > 一定要用$符号隔开! 29 | ## 友链页面 30 | 规则如下: 31 | ``` 32 | #格式一定要对,否则出错 33 | - 博客名|[博客地址](博客地址)|头像地址|博客简介 34 | - 林尽欢|[https://iobiji.com](https://iobiji.com)|https://cdn.iobiji.com/202001/jinhuan.jpg|我最不喜欢做选择,但我选择了,就一定不后悔。 35 | ``` 36 | ## Gravatar 镜像源 37 | - gravatar官方www源 https://www.gravatar.com/avatar/ 38 | - gravatar官方cn源 https://cn.gravatar.com/avatar/ 39 | - gravatar官方en源 https://en.gravatar.com/avatar/ 40 | - gravatar官方secure源 https://secure.gravatar.com/avatar/ 41 | - V2EX源 https://cdn.v2ex.com/gravatar/ 42 | - Loli源 https://gravatar.loli.net/avatar/ 43 | - 极客族 https://sdn.geekzu.org/avatar/ 44 | ### License 45 | 46 | Typecho Theme Spring is open source and released under the MIT License. 47 | -------------------------------------------------------------------------------- /assets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unsafe-ptr/Spring/23d1f9522acf20328441432340609cef3cc74082/assets/.DS_Store -------------------------------------------------------------------------------- /assets/css/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unsafe-ptr/Spring/23d1f9522acf20328441432340609cef3cc74082/assets/css/.DS_Store -------------------------------------------------------------------------------- /assets/css/comments.css: -------------------------------------------------------------------------------- 1 | .v * { 2 | -webkit-box-sizing: border-box; 3 | box-sizing: border-box; 4 | line-height: 2; 5 | color: #555; 6 | -webkit-transition: all .3s ease; 7 | transition: all .3s ease 8 | } 9 | 10 | .v hr { 11 | margin: .825rem 0; 12 | border-color: #f6f6f6; 13 | border-style: dashed 14 | } 15 | 16 | .v.hide-avatar .vimg { 17 | display: none 18 | } 19 | 20 | .v a { 21 | position: relative; 22 | cursor: pointer; 23 | color: #1abc9c; 24 | display: inline-block 25 | } 26 | 27 | .v a:before { 28 | content: ""; 29 | position: absolute; 30 | width: 0; 31 | right: 0; 32 | bottom: 0; 33 | height: 1px; 34 | background: #1abc9c; 35 | -webkit-transition: width .3s ease; 36 | transition: width .3s ease 37 | } 38 | 39 | .v a:hover { 40 | color: #d7191a 41 | } 42 | 43 | .v a:hover:before { 44 | width: 100%; 45 | left: 0; 46 | right: auto 47 | } 48 | 49 | .v code, .v pre { 50 | background-color: #f6f6f6; 51 | color: #555; 52 | padding: .2em .4em; 53 | border-radius: 3px; 54 | font-size: 85%; 55 | margin: 0; 56 | font-family: Source Code Pro, courier new, Input Mono, PT Mono, SFMono-Regular, Consolas, Monaco, Menlo, PingFang SC, Liberation Mono, Microsoft YaHei, Courier,monospace 57 | } 58 | 59 | .v pre { 60 | padding: 10px; 61 | overflow: auto; 62 | line-height: 1.45 63 | } 64 | 65 | .v pre code { 66 | padding: 0; 67 | background: transparent; 68 | white-space: pre-wrap; 69 | word-break: keep-all 70 | } 71 | 72 | .v blockquote { 73 | color: #666; 74 | margin: .5rem 0; 75 | padding: 0 0 0 1rem; 76 | border-left: 8px solid hsla(0, 0%, 93%, .5) 77 | } 78 | 79 | .v .vinput { 80 | border: none; 81 | resize: none; 82 | outline: none; 83 | padding: 10px 5px; 84 | max-width: 100%; 85 | font-size: .775rem 86 | } 87 | 88 | .v input[type=checkbox], .v input[type=radio] { 89 | display: inline-block; 90 | vertical-align: middle; 91 | margin-top: -2px 92 | } 93 | 94 | .v .vwrap { 95 | border: 1px solid #f0f0f0; 96 | border-radius: 4px; 97 | margin-bottom: 10px; 98 | overflow: hidden; 99 | position: relative; 100 | padding: 10px 101 | } 102 | 103 | .v .vwrap input { 104 | background: transparent 105 | } 106 | 107 | .v .vwrap .vedit { 108 | position: relative; 109 | padding-top: 10px 110 | } 111 | 112 | .v .vwrap .vedit .vctrl { 113 | text-align: right; 114 | font-size: 12px 115 | } 116 | 117 | .v .vwrap .vedit .vctrl span { 118 | padding: 10px; 119 | display: inline-block; 120 | vertical-align: middle; 121 | cursor: pointer 122 | } 123 | 124 | .v .vwrap .vedit .vemojis { 125 | display: none; 126 | font-size: 18px; 127 | text-align: justify; 128 | max-height: 145px; 129 | overflow: auto; 130 | margin-bottom: 10px; 131 | -webkit-box-shadow: 0 0 1px #f0f0f0; 132 | box-shadow: 0 0 1px #f0f0f0 133 | } 134 | 135 | .v .vwrap .vedit .vemojis i { 136 | font-style: normal; 137 | padding: 7px 0; 138 | width: 38px; 139 | cursor: pointer; 140 | text-align: center; 141 | display: inline-block; 142 | vertical-align: middle 143 | } 144 | 145 | .v .vwrap .vedit .vpreview { 146 | padding: 7px; 147 | -webkit-box-shadow: 0 0 1px #f0f0f0; 148 | box-shadow: 0 0 1px #f0f0f0 149 | } 150 | 151 | .v .vwrap .vedit .vpreview frame, .v .vwrap .vedit .vpreview iframe, .v .vwrap .vedit .vpreview img { 152 | max-width: 100%; 153 | border: none 154 | } 155 | 156 | .v .vwrap .vheader .vinput { 157 | width: 33.33%; 158 | border-bottom: 1px dashed #dedede 159 | } 160 | 161 | .v .vwrap .vheader.item2 .vinput { 162 | width: 50% 163 | } 164 | 165 | .v .vwrap .vheader.item1 .vinput { 166 | width: 100% 167 | } 168 | 169 | .v .vwrap .vheader .vinput:focus { 170 | border-bottom-color: #eb5055 171 | } 172 | 173 | @media screen and (max-width: 520px) { 174 | .v .vwrap .vheader.item2 .vinput, .v .vwrap .vheader .vinput { 175 | width: 100% 176 | } 177 | } 178 | 179 | .v .vwrap .vcontrol { 180 | font-size: 0; 181 | padding-top: 15px 182 | } 183 | 184 | .v .vwrap .vcontrol .col { 185 | display: inline-block; 186 | font-size: .725rem; 187 | vertical-align: middle; 188 | color: #ccc 189 | } 190 | 191 | .v .vwrap .vcontrol .col.text-right { 192 | text-align: right 193 | } 194 | 195 | .v .vwrap .vcontrol .col svg { 196 | margin-right: 2px; 197 | overflow: hidden; 198 | fill: currentColor; 199 | vertical-align: middle 200 | } 201 | 202 | .v .vwrap .vcontrol .col.col-20 { 203 | width: 20% 204 | } 205 | 206 | .v .vwrap .vcontrol .col.col-40 { 207 | width: 40% 208 | } 209 | 210 | .v .vwrap .vcontrol .col.col-60 { 211 | width: 60% 212 | } 213 | 214 | .v .vwrap .vcontrol .col.col-80 { 215 | width: 80% 216 | } 217 | 218 | .v .vwrap .vcontrol .col.split { 219 | width: 50% 220 | } 221 | 222 | .v .vwrap .vmark { 223 | position: absolute; 224 | background: rgba(0, 0, 0, .65); 225 | width: 100%; 226 | height: 100%; 227 | left: 0; 228 | top: 0 229 | } 230 | 231 | .v .vwrap .vmark .valert { 232 | padding-top: 3rem 233 | } 234 | 235 | .v .vwrap .vmark .valert .vtext { 236 | color: #fff; 237 | padding: 1rem 0 238 | } 239 | 240 | .v .vwrap .vmark .valert .vcode { 241 | width: 4.6875rem; 242 | border-radius: .3125rem; 243 | padding: .5rem; 244 | background: #dedede 245 | } 246 | 247 | .v .vwrap .vmark .valert .vcode:focus { 248 | border-color: #3090e4; 249 | background-color: #fff 250 | } 251 | 252 | @media screen and (max-width: 720px) { 253 | .v .vwrap .vmark .valert { 254 | padding-top: 5.5rem 255 | } 256 | 257 | .v .vwrap .vmark .valert .vtext { 258 | color: #fff; 259 | padding: 1rem 0 260 | } 261 | } 262 | 263 | .v .power { 264 | color: #999; 265 | padding: .5rem 0 266 | } 267 | 268 | .v .power, .v .power a { 269 | font-size: .75rem 270 | } 271 | 272 | .v .vinfo { 273 | font-size: 0; 274 | padding: 5px 275 | } 276 | 277 | .v .vinfo .col { 278 | font-size: .875rem; 279 | display: inline-block; 280 | width: 50%; 281 | vertical-align: middle 282 | } 283 | 284 | .v .vinfo .vcount .vnum { 285 | font-weight: 600; 286 | font-size: 1.25rem 287 | } 288 | 289 | .v a { 290 | text-decoration: none; 291 | color: #555 292 | } 293 | 294 | .v a:hover { 295 | color: #222 296 | } 297 | 298 | .v ol, .v ul { 299 | padding: 0; 300 | margin-left: 1.25rem 301 | } 302 | 303 | .v .txt-center { 304 | text-align: center 305 | } 306 | 307 | .v .txt-right { 308 | text-align: right 309 | } 310 | 311 | .v .pd5 { 312 | padding: 5px 313 | } 314 | 315 | .v .pd10 { 316 | padding: 10px 317 | } 318 | 319 | .v .veditor { 320 | width: 100%; 321 | min-height: 8.75rem; 322 | font-size: .875rem; 323 | background: transparent; 324 | resize: vertical; 325 | -webkit-transition: all .25s ease; 326 | transition: all .25s ease; 327 | font-family: Menlo, "Meslo LG", "Helvetica Neue", Helvetica, Arial, sans-serif, "Microsoft yahei" 328 | } 329 | 330 | .v .vbtn { 331 | -webkit-transition-duration: .4s; 332 | transition-duration: .4s; 333 | text-align: center; 334 | color: #313131; 335 | border: 1px solid #ededed; 336 | border-radius: .3rem; 337 | display: inline-block; 338 | background: #ededed; 339 | margin-bottom: 0; 340 | font-weight: 400; 341 | vertical-align: middle; 342 | -ms-touch-action: manipulation; 343 | touch-action: manipulation; 344 | cursor: pointer; 345 | white-space: nowrap; 346 | padding: .5rem 1.25rem; 347 | font-size: .875rem; 348 | line-height: 1.42857143; 349 | -webkit-user-select: none; 350 | -moz-user-select: none; 351 | -ms-user-select: none; 352 | user-select: none; 353 | outline: none 354 | } 355 | 356 | .v .vbtn + .vbtn { 357 | margin-left: 1.25rem 358 | } 359 | 360 | .v .vbtn:active, .v .vbtn:hover { 361 | color: #3090e4; 362 | border-color: #3090e4; 363 | background-color: #fff 364 | } 365 | 366 | .v .vempty { 367 | padding: 1.25rem; 368 | text-align: center; 369 | color: #999 370 | } 371 | 372 | .v .vlist { 373 | width: 100% 374 | } 375 | 376 | .v .vlist .vcard { 377 | padding-top: 1.5rem; 378 | position: relative; 379 | display: block 380 | } 381 | 382 | .v .vlist .vcard:after { 383 | content: ""; 384 | clear: both; 385 | display: block 386 | } 387 | 388 | .v .vlist .vcard .vimg { 389 | width: 3.125rem; 390 | height: 3.125rem; 391 | float: left; 392 | border-radius: 50%; 393 | margin-right: .7525rem; 394 | border: 1px solid #f5f5f5; 395 | padding: .125rem 396 | } 397 | 398 | @media screen and (max-width: 720px) { 399 | .v .vlist .vcard .vimg { 400 | width: 2.5rem; 401 | height: 2.5rem 402 | } 403 | } 404 | 405 | .v .vlist .vcard .vhead { 406 | line-height: 1.5; 407 | margin-top: 0 408 | } 409 | 410 | .v .vlist .vcard .vhead .vnick { 411 | position: relative; 412 | font-size: .875rem; 413 | font-weight: 500; 414 | margin-right: .875rem; 415 | cursor: pointer; 416 | color: #1abc9c; 417 | text-decoration: none; 418 | display: inline-block 419 | } 420 | 421 | .v .vlist .vcard .vhead .vnick:before { 422 | content: ""; 423 | position: absolute; 424 | width: 0; 425 | right: 0; 426 | bottom: 0; 427 | height: 1px; 428 | background: #1abc9c; 429 | -webkit-transition: width .3s ease; 430 | transition: width .3s ease 431 | } 432 | 433 | .v .vlist .vcard .vhead .vnick:hover { 434 | color: #d7191a 435 | } 436 | 437 | .v .vlist .vcard .vhead .vnick:hover:before { 438 | width: 100%; 439 | left: 0; 440 | right: auto 441 | } 442 | 443 | .v .vlist .vcard .vhead .vsys { 444 | display: inline-block; 445 | padding: .2rem .5rem; 446 | background: #ededed; 447 | color: #b3b1b1; 448 | font-size: .75rem; 449 | border-radius: .2rem; 450 | margin-right: .3rem 451 | } 452 | 453 | @media screen and (max-width: 520px) { 454 | .v .vlist .vcard .vhead .vsys { 455 | display: none 456 | } 457 | } 458 | 459 | .v .vlist .vcard .vh { 460 | overflow: hidden; 461 | padding-bottom: .5rem; 462 | border-bottom: 1px dashed #f5f5f5 463 | } 464 | 465 | .v .vlist .vcard .vh .vtime { 466 | color: #b3b3b3; 467 | font-size: .75rem; 468 | margin-right: .875rem 469 | } 470 | 471 | .v .vlist .vcard .vh .vmeta { 472 | line-height: 1; 473 | position: relative 474 | } 475 | 476 | .v .vlist .vcard .vh .vmeta .vat { 477 | font-size: .8125rem; 478 | color: #ef2f11; 479 | cursor: pointer; 480 | float: right 481 | } 482 | 483 | .v .vlist .vcard .vcontent { 484 | word-wrap: break-word; 485 | word-break: break-all; 486 | text-align: justify; 487 | color: #4a4a4a; 488 | font-size: .875rem; 489 | line-height: 2; 490 | position: relative; 491 | margin-bottom: .75rem; 492 | padding-top: .625rem 493 | } 494 | 495 | .v .vlist .vcard .vcontent frame, .v .vlist .vcard .vcontent iframe, .v .vlist .vcard .vcontent img { 496 | max-width: 100%; 497 | border: none 498 | } 499 | 500 | .v .vlist .vcard .vcontent.expand { 501 | cursor: pointer; 502 | max-height: 11.25rem; 503 | overflow: hidden 504 | } 505 | 506 | .v .vlist .vcard .vcontent.expand:before { 507 | display: block; 508 | content: ""; 509 | position: absolute; 510 | width: 100%; 511 | left: 0; 512 | top: 0; 513 | bottom: 3.15rem; 514 | pointer-events: none; 515 | background: -webkit-gradient(linear, left top, left bottom, from(hsla(0, 0%, 100%, 0)), to(hsla(0, 0%, 100%, .9))); 516 | background: linear-gradient(180deg, hsla(0, 0%, 100%, 0), hsla(0, 0%, 100%, .9)) 517 | } 518 | 519 | .v .vlist .vcard .vcontent.expand:after { 520 | display: block; 521 | content: "Click on expand"; 522 | text-align: center; 523 | color: #828586; 524 | position: absolute; 525 | width: 100%; 526 | height: 3.15rem; 527 | line-height: 3.15rem; 528 | left: 0; 529 | bottom: 0; 530 | pointer-events: none; 531 | background: hsla(0, 0%, 100%, .9) 532 | } 533 | 534 | .v .vlist .vcard .vquote { 535 | color: #666; 536 | margin-top: 1rem; 537 | padding-left: 1rem; 538 | border-left: 1px dashed hsla(0, 0%, 93%, .5) 539 | } 540 | 541 | .v .vlist .vcard .vquote .vimg { 542 | width: 2.225rem; 543 | height: 2.225rem 544 | } 545 | 546 | .v .vpage .vmore { 547 | margin: 1rem 0 548 | } 549 | 550 | .v .clear { 551 | content: ""; 552 | display: block; 553 | clear: both 554 | } 555 | 556 | @-webkit-keyframes spin { 557 | 0% { 558 | -webkit-transform: rotate(0deg); 559 | transform: rotate(0deg) 560 | } 561 | to { 562 | -webkit-transform: rotate(1turn); 563 | transform: rotate(1turn) 564 | } 565 | } 566 | 567 | @keyframes spin { 568 | 0% { 569 | -webkit-transform: rotate(0deg); 570 | transform: rotate(0deg) 571 | } 572 | to { 573 | -webkit-transform: rotate(1turn); 574 | transform: rotate(1turn) 575 | } 576 | } 577 | 578 | @-webkit-keyframes pulse { 579 | 50% { 580 | background: #dcdcdc 581 | } 582 | } 583 | 584 | @keyframes pulse { 585 | 50% { 586 | background: #dcdcdc 587 | } 588 | } 589 | 590 | .v .vloading { 591 | position: relative; 592 | padding: 20px; 593 | display: block; 594 | height: 80px 595 | } 596 | 597 | .v .vloading:before { 598 | -webkit-box-sizing: border-box; 599 | box-sizing: border-box; 600 | content: ""; 601 | position: absolute; 602 | display: inline-block; 603 | top: 20px; 604 | left: 50%; 605 | margin-left: -20px; 606 | width: 40px; 607 | height: 40px; 608 | border: 6px double #a0a0a0; 609 | border-top-color: transparent; 610 | border-bottom-color: transparent; 611 | border-radius: 50%; 612 | -webkit-animation: spin 1s infinite linear; 613 | animation: spin 1s infinite linear 614 | } -------------------------------------------------------------------------------- /assets/img/hero-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unsafe-ptr/Spring/23d1f9522acf20328441432340609cef3cc74082/assets/img/hero-bg.jpg -------------------------------------------------------------------------------- /assets/js/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unsafe-ptr/Spring/23d1f9522acf20328441432340609cef3cc74082/assets/js/.DS_Store -------------------------------------------------------------------------------- /assets/js/commentAjax.js: -------------------------------------------------------------------------------- 1 | var postUrl = location.protocol + '//' + location.host + location.pathname;// 获取文章路径 2 | // 这一步是子评论的监控回复按钮事件 回复的BUTTON添加onclick属性 3 | const replyMsg = (id, author) => { 4 | const tmp = id.replace("comment-", ""); 5 | $("#veditor").focus(); 6 | $('html,body').animate({scrollTop:$('.blog-post-comments').offset().top-70}, 500); 7 | $("#veditor").attr("placeholder", "@" + author); 8 | $("#veditor").attr("parent", id); 9 | $("#comment-form").attr("action", postUrl + "/comment?parent=" + tmp); 10 | }; 11 | // 依赖jquery,请自行加载 12 | $(() => { 13 | // 监听评论表单提交 14 | $('#comment-form').submit(() => { 15 | let params = $('#comment-form').serialize(); 16 | // 添加functions.php中定义的判断参数 17 | params += '&Ajax=comment'; 18 | // 解析新评论并附加到评论列表 19 | const appendComment = (comment) => { 20 | // 评论列表 21 | let el = $('.comment-list'); 22 | if (comment.parent !== 0) { 23 | // 子评论则重新定位评论列表 24 | el = $('#comment-' + comment.parent); 25 | // 父评论不存在子评论时 26 | if (el.find('.comment-list').length < 1) { 27 | $('
    ').appendTo(el); 28 | } 29 | el = el.find('#parent-' + comment.parent); 30 | } 31 | if (el.length === 0) { 32 | $('
      ').appendTo($('#comments')); 33 | el = $('#comments > .comment-list'); 34 | } 35 | // 评论html模板,根据具体主题定制 36 | let html = '
      {author}{browser} {os}
      {datetime}回复
      {content}
      \n'; 37 | if ($("#veditor").attr("parent") !== null) { 38 | html = '
      {author}{browser} {os}
      {datetime}回复

      @{author} {content}

      \n'; 39 | } 40 | $.each(comment, (k, v) => { 41 | regExp = new RegExp('{' + k + '}', 'g'); 42 | html = html.replace(regExp, v); 43 | }); 44 | $(html).appendTo(el); 45 | }; 46 | // ajax提交评论 47 | $.ajax({ 48 | url: $("#comment-form").attr("action"), 49 | type: 'POST', 50 | data: params, 51 | dataType: 'json', 52 | beforeSend: () => { 53 | $('#comment-form').find('.vsubmit').addClass('loading').html(' 提交中...').attr('disabled', 'disabled'); 54 | }, 55 | complete: () => { 56 | $('#comment-form').find('.vsubmit').removeClass('loading').html('提交评论').removeAttr('disabled'); 57 | }, 58 | success: (result) => { 59 | if (result.status === 1) { 60 | // 新评论附加到评论列表 61 | appendComment(result.comment); 62 | $('#comment-form').find('textarea').val(''); 63 | } else { 64 | // 提醒错误消息 65 | alert(undefined === result.msg ? '评论出错' : result.msg); 66 | } 67 | }, 68 | error: (xhr, ajaxOptions, thrownError) => { 69 | alert('评论失败,请重试'); 70 | } 71 | }); 72 | return false; 73 | }); 74 | }); -------------------------------------------------------------------------------- /assets/js/pjax.js: -------------------------------------------------------------------------------- 1 | var loadFiles = { 2 | js: [], 3 | css: [] 4 | }; 5 | (function ($) { 6 | function getBaseUrl() { 7 | var ishttps = 'https:' == document.location.protocol ? true : false; 8 | var url = window.location.host; 9 | if (ishttps) { 10 | url = 'https://' + url; 11 | } else { 12 | url = 'http://' + url; 13 | } 14 | return url; 15 | } 16 | 17 | /** 18 | * 动态加载JS文件的方法 19 | * Load javascript file method 20 | * 21 | * @param {String} fileName JS文件名 22 | * @param {Function} [callback=function()] 加载成功后执行的回调函数 23 | * @param {String} [into='head'] 嵌入页面的位置 24 | */ 25 | function loadScript(fileName, callback, into) { 26 | into = into || 'body'; 27 | callback = callback || function () { 28 | }; 29 | var script = null; 30 | script = document.createElement('script'); 31 | script.type = 'text/javascript'; 32 | script.src = fileName; 33 | script.onload = function () { 34 | loadFiles.js.push(fileName); 35 | callback(); 36 | }; 37 | if (into === 'head') { 38 | document.getElementsByTagName('head')[0].appendChild(script); 39 | } else { 40 | document.body.appendChild(script); 41 | } 42 | } 43 | 44 | /** 45 | * 动态加载CSS文件的方法 46 | * Load css file method 47 | * 48 | * @param {String} fileName CSS文件名 49 | * @param {Function} [callback=function()] 加载成功后执行的回调函数 50 | * @param {String} [into='head'] 嵌入页面的位置 51 | */ 52 | function loadCSS(fileName, callback, into) { 53 | into = into || 'head'; 54 | callback = callback || function () { 55 | }; 56 | 57 | var css = document.createElement('link'); 58 | css.type = 'text/css'; 59 | css.rel = 'stylesheet'; 60 | css.onload = css.onreadystatechange = function () { 61 | loadFiles.css.push(fileName); 62 | callback(); 63 | }; 64 | css.href = fileName; 65 | if (into === 'head') { 66 | document.getElementsByTagName('head')[0].appendChild(css); 67 | } else { 68 | document.body.appendChild(css); 69 | } 70 | } 71 | 72 | let url = '"' + getBaseUrl() + '"'; 73 | $(document).pjax('a[href^=' + url + ']:not(a[target="_blank"], a[no-pjax])', { 74 | container: '#pjax', 75 | fragment: '#pjax', 76 | timeout: 8000 77 | }); 78 | $(document).on('pjax:send', function () { 79 | $('body').addClass('overflow-hidden'); 80 | $('.pjax-loading-wrapper').fadeIn(); 81 | }); 82 | $(document).on('pjax:complete', function () { 83 | $('.site-wrapper').removeClass('toggled'); 84 | $('.sidebar-container').removeClass('boxshadow-right'); 85 | $('.global-modal').remove(); 86 | $('.site-tooltip-wrapper').remove(); 87 | $('.site-popover-wrapper').remove(); 88 | $('body').removeClass('overflow-hidden'); 89 | setTimeout(() => { 90 | $('.pjax-loading-wrapper').fadeOut('slow'); 91 | }, 800); 92 | if (checkValine === 1) { 93 | loadScript('//cdn.jsdelivr.net/npm/leancloud-storage/dist/av-min.js', function () { 94 | loadScript( 95 | 'https://cdn.jsdelivr.net/npm/valine/dist/Valine.min.js', 96 | function () { 97 | if (document.getElementById('vcomments') !== null) { 98 | new Valine({ 99 | el: '#vcomments', 100 | appId: 'options->APPID()?>', 101 | appKey: 'options->APPKEY()?>', 102 | notify: true, 103 | verify: true, 104 | avatar: 'mm', 105 | visitor: true, // 文章访问量统计 106 | highlight: true, // 代码高亮 107 | recordIP: true, // 是否记录评论者IP 108 | placeholder: '人生在世,错别字在所难免,无需纠正。' 109 | }); 110 | } 111 | } 112 | ); 113 | }); 114 | } 115 | // 自定义脚本回调 116 | if (typeof window.ga !== 'undefined') window.ga('send', 'pageview', window.location.pathname + window.location.search); 117 | if (typeof window._hmt !== 'undefined') window._hmt.push(['_trackPageview', window.location.pathname + window.location.search]); 118 | loadScript("https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/js/bootstrap.bundle.min.js"); 119 | loadScript("https://cdn.jsdelivr.net/npm/scrollreveal@4.0.5/dist/scrollreveal.min.js"); 120 | loadScript(bundle); 121 | loadCSS(styleCss); 122 | loadCSS(stylesCss); 123 | }); 124 | loadScript("https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/js/bootstrap.bundle.min.js"); 125 | loadScript("https://cdn.jsdelivr.net/npm/scrollreveal@4.0.5/dist/scrollreveal.min.js"); 126 | loadScript(bundle); 127 | loadCSS(styleCss); 128 | loadCSS(stylesCss); 129 | })(jQuery); 130 | window.onload = function () { 131 | console.log('已经动态加载资源:', loadFiles); 132 | }; -------------------------------------------------------------------------------- /comments.php: -------------------------------------------------------------------------------- 1 | 2 | authorId) { 7 | if ($comments->authorId == $comments->ownerId) { 8 | $commentClass .= ' comment-by-author'; 9 | } else { 10 | $commentClass .= ' comment-by-user'; 11 | } 12 | } 13 | 14 | $commentLevelClass = $comments->levels > 0 ? ' comment-child' : ' comment-parent'; 15 | ?> 16 | commentsAvatarRating; 20 | $hash = md5(strtolower($comments->mail)); 21 | $email = strtolower($comments->mail); 22 | $qq = str_replace('@qq.com', '', $email); 23 | if (strstr($email, "qq.com") && is_numeric($qq) && strlen($qq) < 11 && strlen($qq) > 4) { 24 | $avatar = '//q3.qlogo.cn/g?b=qq&nk=' . $qq . '&s=100'; 25 | } else { 26 | $avatar = $host . $url . $hash . '?s=50' . '&r=' . $rating . '&d=mm'; 27 | } 28 | ?> 29 |
      30 |
      31 | 32 |
      33 |
      34 | author(); ?>agent); ?>agent); ?> 37 |
      38 |
      39 | dateWord(); ?> 40 | 回复 41 |
      42 |
      43 | coid); ?> 44 |
      45 |
      46 |
      47 | children) { ?> 48 | threadedComments($options); ?> 49 | 50 |
      51 | 52 | comments()->to($comments); ?> 53 | allow('comment')): ?> 54 |
      55 |
      56 | user->hasLogin()): ?> 57 |
      user->screenName(); ?>. 58 | »
      59 |
      60 |
      61 |
      62 |
      63 | 64 |
      65 |
      66 | 74 |
      75 | 76 | widget('Widget_Security'); ?> 77 |
      78 |
      79 | 81 |
      82 | 83 |
      84 |
      85 | options->commentsRequireMail): ?> required>options->commentsRequireMail): ?> required> 91 | 92 |
      93 | 94 |
      95 | 96 |
      97 |
      98 | 106 |
      107 | 108 | 109 | widget('Widget_Security'); ?> 110 | 111 |
      112 |
      113 | 114 | 116 |
      117 | 118 |
      119 | commentsNum != 0): ?> 120 |
      121 |
      122 | commentsNum('%d'); ?> 评论 123 |
      124 |
      125 | 126 |
      快来做第一个评论的人吧~
      127 | 128 | have()): ?> 129 | listComments(); ?> 130 | 131 | 132 | pageNav('', '', 10, '', array('wrapTag' => 'div', 'wrapClass' => 'pagination', 'itemTag' => '', 'currentClass' => 'page-number',)); ?> 133 | 134 | -------------------------------------------------------------------------------- /footer.php: -------------------------------------------------------------------------------- 1 | options->cdn) && $this->options->cdn) { 4 | define('__TYPECHO_THEME_URL__', Typecho_Common::url(__TYPECHO_THEME_DIR__ . '/' . basename(dirname(__FILE__)), $this->options->cdn)); 5 | } 6 | ?> 7 | 20 | 43 | 60 | 61 |
      62 |
      63 |
      64 | 67 |
      68 | 76 |
      77 |
      78 |
      79 | 80 |
      81 | 82 | is('post')): ?> 83 | 84 | 85 |
      86 | 87 | 88 |
      89 |
      90 |
      91 | 92 | 94 | 95 | 96 | 97 | 112 | 117 | 118 | footer(); ?> 119 | 120 | 121 | -------------------------------------------------------------------------------- /full-width-for-post.php: -------------------------------------------------------------------------------- 1 | 2 | need('header.php'); 12 | ?> 13 |
      14 |
      16 |
      17 |
      title; ?>
      18 |
      author(); ?> 19 | / created) ?> 20 | / / 阅读量
      21 |
      22 |
      23 | 25 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
      37 |
      38 | 39 |
      40 |
      41 |
      42 |
      43 | content); ?> 44 |
      45 |
      46 |
      47 | 58 | 69 |
      70 |
      71 |
      72 | options->alipay != null): ?> 73 |
      74 |
      75 | 支付宝捐赠 76 |
      请使用支付宝扫一扫进行捐赠
      77 |
      78 |
      79 | 80 | options->wpay != null): ?> 81 |
      82 |
      83 | 微信捐赠 84 |
      请使用微信扫一扫进行赞赏
      85 |
      86 |
      87 | 88 |
      89 |
      90 |
      91 |
      92 | 107 | 149 | 150 | 255 | 256 |
      257 | 258 | 259 | need('comments.php'); ?> 260 | 261 |
      262 |
      263 | 264 |
      265 |
      266 |
      267 | need('footer.php'); ?> 268 | -------------------------------------------------------------------------------- /functions.php: -------------------------------------------------------------------------------- 1 | Gravatar ? Helper::options()->Gravatar : '//cdn.v2ex.com/gravatar/'); 6 | require_once 'lib/Utils.php'; 7 | require_once 'lib/Comments.php'; 8 | if (!empty(Helper::options()->cdn)) { 9 | define('__TYPECHO_UPLOAD_URL__', $_SERVER['REQUEST_SCHEME'] . '://' . Helper::options()->cdn); 10 | } 11 | function themeConfig($form) 12 | { 13 | echo ''; 14 | ?> 15 | 345 | Ver ' . Spring_VERSION . ' 347 |

      Theme-Spring

      348 |

      感谢选择使用 Spring

      349 |

      issue

      350 | '; 351 | $bgUrl = new Typecho_Widget_Helper_Form_Element_Text('bgUrl', NULL, 'https://www.bing.com/th?id=OHR.Lunarnewyeareve2020_ZH-CN1514309048_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=HpEdgeAn', _t('首页背景图片'), _t('在这里填入一个图片 URL 地址')); 352 | $Gravatar = new Typecho_Widget_Helper_Form_Element_Text('Gravatar', NULL, NULL, _t('自定义 Gravatar 源'), _t('输入Gravatar源,如https://cdn.v2ex.com/gravatar/')); 353 | $cdn = new Typecho_Widget_Helper_Form_Element_Text('cdn', NULL, NULL, _t('使用自己的静态存储'), _t('输入静态存储链接(不需要带http/https)')); 354 | $APPID = new Typecho_Widget_Helper_Form_Element_Text('APPID', NULL, NULL, _t('APP ID'), _t('输入在Valine获取的APP ID')); 355 | $APPKEY = new Typecho_Widget_Helper_Form_Element_Text('APPKEY', NULL, NULL, _t('APP KEY'), _t('输入在Valine获取的APP KEY')); 356 | $serverURLs = new Typecho_Widget_Helper_Form_Element_Text('serverURLs', NULL, NULL, _t('Valine安全域名'), _t('输入在Valine设置的安全域名')); 357 | $weibo = new Typecho_Widget_Helper_Form_Element_Text('weibo', NULL, '#', _t('微博地址'), _t('输入微博地址')); 358 | $beian = new Typecho_Widget_Helper_Form_Element_Text('beian', NULL, NULL, _t('ICP备案号'), _t('')); 359 | $Subtitle = new Typecho_Widget_Helper_Form_Element_Text('Subtitle', NULL, NULL, _t('站点副标题'), _t('')); 360 | $alipay = new Typecho_Widget_Helper_Form_Element_Text('alipay', NULL, NULL, _t('支付宝收款二维码链接'), _t('')); 361 | $wpay = new Typecho_Widget_Helper_Form_Element_Text('wpay', NULL, NULL, _t('微信收款二维码链接'), _t('')); 362 | $qiniu = new Typecho_Widget_Helper_Form_Element_Text('qiniu', NULL, NULL, _t('七牛云替换全站镜像'), _t('需要带http/https')); 363 | $github = new Typecho_Widget_Helper_Form_Element_Text('github', NULL, '#', _t('GITHUB'), _t('')); 364 | $QQGROUP = new Typecho_Widget_Helper_Form_Element_Text('QQGROUP', NULL, '#', _t('QQ群链接'), _t('')); 365 | $ititle = new Typecho_Widget_Helper_Form_Element_Text('ititle', NULL, '首页标题', _t('首页标题'), _t('')); 366 | $Logo = new Typecho_Widget_Helper_Form_Element_Text('Logo', NULL, '网站logo', _t('网站logo'), _t('')); 367 | $form->addInput($bgUrl); 368 | $form->addInput($Logo); 369 | $form->addInput($ititle); 370 | $form->addInput($Subtitle); 371 | $form->addInput($beian); 372 | $form->addInput($qiniu); 373 | $form->addInput($weibo); 374 | $form->addInput($Gravatar); 375 | $form->addInput($cdn); 376 | $form->addInput($APPID); 377 | $form->addInput($APPKEY); 378 | $form->addInput($serverURLs); 379 | $form->addInput($alipay); 380 | $form->addInput($wpay); 381 | $form->addInput($github); 382 | $form->addInput($QQGROUP); 383 | $JConfig = new Typecho_Widget_Helper_Form_Element_Checkbox('JConfig', 384 | array( 385 | 'enableComments' => '开启主题自带评论系统' 386 | ), 387 | [], 388 | '开关设置' 389 | ); 390 | $form->addInput($JConfig->multiMode()); 391 | } 392 | 393 | function themeFields($layout) 394 | { 395 | //$showTOC = new Typecho_Widget_Helper_Form_Element_Radio('showTOC', array(true => _t('开启'), false => _t('关闭')), false, _t('TOC文章目录解析'), _t('1代表开启,0代表关闭,解析h1-h6标签')); 396 | $previewContent = new Typecho_Widget_Helper_Form_Element_Text('previewContent', NULL, NULL, _t('文章摘要'), _t('设置文章的预览内容,留空自动截取文章前55个字。')); 397 | $thumbnail = new Typecho_Widget_Helper_Form_Element_Text('thumbnail', NULL, NULL, _t('文章/页面缩略图Url'), _t('需要带上http(s)://')); 398 | $layout->addItem($thumbnail); 399 | //$layout->addItem($showTOC); 400 | $layout->addItem($previewContent); 401 | } 402 | 403 | function get_post_view($archive) 404 | { 405 | $cid = $archive->cid; 406 | $db = Typecho_Db::get(); 407 | $prefix = $db->getPrefix(); 408 | if (!array_key_exists('views', $db->fetchRow($db->select()->from('table.contents')))) { 409 | $db->query('ALTER TABLE `' . $prefix . 'contents` ADD `views` INT(10) DEFAULT 0;'); 410 | echo 0; 411 | return; 412 | } 413 | $row = $db->fetchRow($db->select('views')->from('table.contents')->where('cid = ?', $cid)); 414 | if ($archive->is('single')) { 415 | $views = Typecho_Cookie::get('extend_contents_views'); 416 | if (empty($views)) { 417 | $views = array(); 418 | } else { 419 | $views = explode(',', $views); 420 | } 421 | if (!in_array($cid, $views)) { 422 | $db->query($db->update('table.contents')->rows(array('views' => (int)$row['views'] + 1))->where('cid = ?', $cid)); 423 | array_push($views, $cid); 424 | $views = implode(',', $views); 425 | Typecho_Cookie::set('extend_contents_views', $views); //记录查看cookie 426 | } 427 | } 428 | echo $row['views']; 429 | } 430 | 431 | function themeInit($archive) 432 | { 433 | // 判断是否是添加评论的操作 434 | // 为文章或页面、post操作,且包含参数`themeAction=comment`(自定义) 435 | if ($archive->is('single') && $archive->request->isPost() && $archive->request->is('Ajax=comment')) { 436 | // 为添加评论的操作时 437 | ajaxComment($archive); 438 | } 439 | } 440 | 441 | /** 442 | * ajaxComment 443 | * 实现Ajax评论的方法(实现feedback中的comment功能) 444 | * @param Widget_Archive $archive 445 | * @return void 446 | */ 447 | function ajaxComment($archive) 448 | { 449 | $options = Helper::options(); 450 | $user = Typecho_Widget::widget('Widget_User'); 451 | $db = Typecho_Db::get(); 452 | // Security 验证不通过时会直接跳转,所以需要自己进行判断 453 | // 需要开启反垃圾保护,此时将不验证来源 454 | if ($archive->request->get('_') != Helper::security()->getToken($archive->request->getReferer())) { 455 | $archive->response->throwJson(array('status' => 0, 'msg' => _t('非法请求'))); 456 | } 457 | /** 评论关闭 */ 458 | if (!$archive->allow('comment')) { 459 | $archive->response->throwJson(array('status' => 0, 'msg' => _t('评论已关闭'))); 460 | } 461 | /** 检查ip评论间隔 */ 462 | if (!$user->pass('editor', true) && $archive->authorId != $user->uid && 463 | $options->commentsPostIntervalEnable) { 464 | $latestComment = $db->fetchRow($db->select('created')->from('table.comments') 465 | ->where('cid = ?', $archive->cid) 466 | ->where('ip = ?', $archive->request->getIp()) 467 | ->order('created', Typecho_Db::SORT_DESC) 468 | ->limit(1)); 469 | 470 | if ($latestComment && ($options->gmtTime - $latestComment['created'] > 0 && 471 | $options->gmtTime - $latestComment['created'] < $options->commentsPostInterval)) { 472 | $archive->response->throwJson(array('status' => 0, 'msg' => _t('对不起, 您的发言过于频繁, 请稍侯再次发布'))); 473 | } 474 | } 475 | 476 | $comment = array( 477 | 'cid' => $archive->cid, 478 | 'created' => $options->gmtTime, 479 | 'agent' => $archive->request->getAgent(), 480 | 'ip' => $archive->request->getIp(), 481 | 'ownerId' => $archive->author->uid, 482 | 'type' => 'comment', 483 | 'status' => !$archive->allow('edit') && $options->commentsRequireModeration ? 'waiting' : 'approved' 484 | ); 485 | 486 | /** 判断父节点 */ 487 | if ($parentId = $archive->request->filter('int')->get('parent')) { 488 | if ($options->commentsThreaded && ($parent = $db->fetchRow($db->select('coid', 'cid')->from('table.comments') 489 | ->where('coid = ?', $parentId))) && $archive->cid == $parent['cid']) { 490 | $comment['parent'] = $parentId; 491 | } else { 492 | $archive->response->throwJson(array('status' => 0, 'msg' => _t('父级评论不存在'))); 493 | } 494 | } 495 | $feedback = Typecho_Widget::widget('Widget_Feedback'); 496 | //检验格式 497 | $validator = new Typecho_Validate(); 498 | $validator->addRule('author', 'required', _t('必须填写用户名')); 499 | $validator->addRule('author', 'xssCheck', _t('请不要在用户名中使用特殊字符')); 500 | $validator->addRule('author', array($feedback, 'requireUserLogin'), _t('您所使用的用户名已经被注册,请登录后再次提交')); 501 | $validator->addRule('author', 'maxLength', _t('用户名最多包含200个字符'), 200); 502 | 503 | if ($options->commentsRequireMail && !$user->hasLogin()) { 504 | $validator->addRule('mail', 'required', _t('必须填写电子邮箱地址')); 505 | } 506 | 507 | $validator->addRule('mail', 'email', _t('邮箱地址不合法')); 508 | $validator->addRule('mail', 'maxLength', _t('电子邮箱最多包含200个字符'), 200); 509 | 510 | if ($options->commentsRequireUrl && !$user->hasLogin()) { 511 | $validator->addRule('url', 'required', _t('必须填写个人主页')); 512 | } 513 | $validator->addRule('url', 'url', _t('个人主页地址格式错误')); 514 | $validator->addRule('url', 'maxLength', _t('个人主页地址最多包含200个字符'), 200); 515 | 516 | $validator->addRule('text', 'required', _t('必须填写评论内容')); 517 | 518 | $comment['text'] = $archive->request->text; 519 | 520 | /** 对一般匿名访问者,将用户数据保存一个月 */ 521 | if (!$user->hasLogin()) { 522 | /** Anti-XSS */ 523 | $comment['author'] = $archive->request->filter('trim')->author; 524 | $comment['mail'] = $archive->request->filter('trim')->mail; 525 | $comment['url'] = $archive->request->filter('trim')->url; 526 | 527 | /** 修正用户提交的url */ 528 | if (!empty($comment['url'])) { 529 | $urlParams = parse_url($comment['url']); 530 | if (!isset($urlParams['scheme'])) { 531 | $comment['url'] = 'http://' . $comment['url']; 532 | } 533 | } 534 | 535 | $expire = $options->gmtTime + $options->timezone + 30 * 24 * 3600; 536 | Typecho_Cookie::set('__typecho_remember_author', $comment['author'], $expire); 537 | Typecho_Cookie::set('__typecho_remember_mail', $comment['mail'], $expire); 538 | Typecho_Cookie::set('__typecho_remember_url', $comment['url'], $expire); 539 | } else { 540 | $comment['author'] = $user->screenName; 541 | $comment['mail'] = $user->mail; 542 | $comment['url'] = $user->url; 543 | 544 | /** 记录登录用户的id */ 545 | $comment['authorId'] = $user->uid; 546 | } 547 | 548 | /** 评论者之前须有评论通过了审核 */ 549 | if (!$options->commentsRequireModeration && $options->commentsWhitelist) { 550 | if ($feedback->size($feedback->select()->where('author = ? AND mail = ? AND status = ?', $comment['author'], $comment['mail'], 'approved'))) { 551 | $comment['status'] = 'approved'; 552 | } else { 553 | $comment['status'] = 'waiting'; 554 | } 555 | } 556 | 557 | if ($error = $validator->run($comment)) { 558 | $archive->response->throwJson(array('status' => 0, 'msg' => implode(';', $error))); 559 | } 560 | 561 | /** 添加评论 */ 562 | if (preg_match("/[\x{4e00}-\x{9fa5}]/u", $comment['text']) == 0) { 563 | $archive->response->throwJson(array('status' => 0, 'msg' => _t('评论内容请不少于一个中文汉字'))); 564 | } 565 | $commentId = $feedback->insert($comment); 566 | if (!$commentId) { 567 | $archive->response->throwJson(array('status' => 0, 'msg' => _t('评论失败'))); 568 | } 569 | Typecho_Cookie::delete('__typecho_remember_text'); 570 | $db->fetchRow($feedback->select()->where('coid = ?', $commentId) 571 | ->limit(1), array($feedback, 'push')); 572 | $feedback->pluginHandle()->finishComment($feedback); 573 | // 返回评论数据 574 | $data = array( 575 | 'cid' => $feedback->cid, 576 | 'coid' => $feedback->coid, 577 | 'parent' => $feedback->parent, 578 | 'mail' => $feedback->mail, 579 | 'url' => $feedback->url, 580 | 'ip' => $feedback->ip, 581 | 'browser' => getBrowser($feedback->agent), 582 | 'os' => getOs($feedback->agent), 583 | 'author' => $feedback->author, 584 | 'authorId' => $feedback->authorId, 585 | 'permalink' => $feedback->permalink, 586 | 'created' => $feedback->created, 587 | 'datetime' => $feedback->date->format('Y-m-d H:i:s'), 588 | 'status' => $feedback->status, 589 | ); 590 | // 评论内容 591 | ob_start(); 592 | $feedback->content(); 593 | $data['content'] = ob_get_clean(); 594 | preg_match("~

      (.*)

      ~", $data['content'], $newcontent); 595 | $data['content'] = $newcontent[1]; 596 | 597 | $data['avatar'] = Typecho_Common::gravatarUrl($data['mail'], 48, Helper::options()->commentsAvatarRating, NULL, $archive->request->isSecure()); 598 | $archive->response->throwJson(array('status' => 1, 'comment' => $data)); 599 | } 600 | 601 | function getCommentAt($coid) 602 | { 603 | $db = Typecho_Db::get(); 604 | $prow = $db->fetchRow($db->select('parent') 605 | ->from('table.comments') 606 | ->where('coid = ? AND status = ?', $coid, 'approved')); 607 | $parent = $prow['parent']; 608 | if ($parent != "0") { 609 | $arow = $db->fetchRow($db->select('author') 610 | ->from('table.comments') 611 | ->where('coid = ? AND status = ?', $parent, 'approved')); 612 | $author = $arow['author']; 613 | $href = '@' . $author . ''; 614 | //$href = '@'.$author; 615 | return $href; 616 | } else { 617 | return ''; 618 | } 619 | } 620 | 621 | function ounts($sum, $total) 622 | { 623 | if ($sum > $total) { 624 | $sum -= 1; 625 | return ounts($sum, $total); 626 | } else { 627 | return $sum; 628 | } 629 | } 630 | 631 | /** 632 | * 随机输出文章 633 | * 634 | * @access public 635 | */ 636 | function posts($widget) 637 | { 638 | $db = Typecho_Db::get(); 639 | $sql = $db->select()->from('table.contents') 640 | ->where('table.contents.status = ?', 'publish') 641 | ->where('table.contents.type = ?', $widget->type) 642 | ->where('table.contents.password IS NULL') 643 | ->order('table.contents.created', Typecho_Db::SORT_ASC); 644 | $data = $db->fetchALL($sql); 645 | $total = count($data); 646 | $nums = ounts(3, $total); 647 | $temp = array_rand($data, $nums); 648 | $content = array(); 649 | foreach ($temp as $val) { 650 | $content[] = $data[$val]; 651 | } 652 | if ($content) { 653 | $arr = array(); 654 | foreach ($content as $key => $v) { 655 | $contents = $widget->filter($content[$key]); 656 | $arr[$key]['title'] = $contents['title']; 657 | $arr[$key]['url'] = $contents['permalink']; 658 | //$arr[$key]['category'] = $contents['categories'][0]['name']; 659 | //$arr[$key]['timeStamp'] = $contents['date']->timeStamp; 660 | } 661 | return $arr; 662 | } else { 663 | return false; 664 | } 665 | } 666 | 667 | function excerpt($post_excerpt) 668 | { 669 | $post_excerpt = strip_tags(htmlspecialchars_decode($post_excerpt)); 670 | $post_excerpt = trim($post_excerpt); 671 | 672 | $patternArr = array('/\s/', '/ /'); 673 | $replaceArr = array('', ''); 674 | $post_excerpt = preg_replace($patternArr, $replaceArr, $post_excerpt); 675 | $value = mb_strcut($post_excerpt, 0, 400, 'utf-8'); 676 | return $value; 677 | } 678 | 679 | /** 680 | * 显示下一篇 681 | * 682 | * @access public 683 | */ 684 | function theNext($widget) 685 | { 686 | $db = Typecho_Db::get(); 687 | $sql = $db->select()->from('table.contents') 688 | ->where('table.contents.created > ?', $widget->created) 689 | ->where('table.contents.status = ?', 'publish') 690 | ->where('table.contents.type = ?', $widget->type) 691 | ->where('table.contents.password IS NULL') 692 | ->order('table.contents.created', Typecho_Db::SORT_ASC) 693 | ->limit(1); 694 | $content = $db->fetchRow($sql); 695 | $arr = array(); 696 | $fields = array(); 697 | $rows = $db->fetchAll($db->select()->from('table.fields') 698 | ->where('cid = ?', $content['cid'])); 699 | foreach ($rows as $row) { 700 | $fields[$row['name']] = $row[$row['type'] . '_value']; 701 | } 702 | if ($content) { 703 | $content = $widget->filter($content); 704 | $arr['url'] = $content['permalink']; 705 | $arr['title'] = $content['title']; 706 | $arr['content'] = excerpt($content['text']); 707 | $arr['thumbnail'] = $fields['thumbnail']; 708 | $arr['category'] = $content['categories'][0]['name']; 709 | $arr['rate'] = getRate($content['text']); 710 | return $arr; 711 | } else { 712 | return false; 713 | } 714 | } 715 | 716 | /** 717 | * 显示上一篇 718 | * 719 | * @access public 720 | */ 721 | function thePrev($widget) 722 | { 723 | $db = Typecho_Db::get(); 724 | $sql = $db->select()->from('table.contents') 725 | ->where('table.contents.created < ?', $widget->created) 726 | ->where('table.contents.status = ?', 'publish') 727 | ->where('table.contents.type = ?', $widget->type) 728 | ->where('table.contents.password IS NULL') 729 | ->order('table.contents.created', Typecho_Db::SORT_DESC) 730 | ->limit(1); 731 | $content = $db->fetchRow($sql); 732 | $arr = array(); 733 | $fields = array(); 734 | $rows = $db->fetchAll($db->select()->from('table.fields') 735 | ->where('cid = ?', $content['cid'])); 736 | foreach ($rows as $row) { 737 | $fields[$row['name']] = $row[$row['type'] . '_value']; 738 | } 739 | if ($content) { 740 | $content = $widget->filter($content); 741 | $arr['url'] = $content['permalink']; 742 | $arr['title'] = $content['title']; 743 | $arr['content'] = excerpt($content['text']); 744 | $arr['thumbnail'] = $fields['thumbnail']; 745 | $arr['category'] = $content['categories'][0]['name']; 746 | $arr['rate'] = getRate($content['text']); 747 | return $arr; 748 | } else { 749 | return false; 750 | } 751 | } 752 | 753 | function getRate($content) 754 | { 755 | $speed = 300; 756 | $nums = preg_replace('/[\x80-\xff]{1,3}/', ' ', $content, -1); 757 | $nums = strlen($nums); 758 | $rate = ceil($nums / $speed); 759 | return $rate; 760 | } 761 | 762 | function getCategory($widget) 763 | { 764 | $db = Typecho_Db::get(); 765 | $sql = $db->select()->from('table.contents') 766 | ->where('table.contents.cid = ?', $widget->cid); 767 | $content = $db->fetchRow($sql); 768 | $arr = array(); 769 | if ($content) { 770 | $content = $widget->filter($content); 771 | $arr['category'] = $content['categories'][0]['name']; 772 | $arr['url'] = $content['categories'][0]['permalink']; 773 | return $arr; 774 | } else { 775 | return false; 776 | } 777 | } 778 | 779 | function spam_protection_math() 780 | { 781 | $num1 = 1; 782 | $num2 = rand(1, 9); 783 | echo "$num1 + $num2 = "; 784 | echo "\n"; 785 | echo "\n"; 786 | echo ""; 787 | } 788 | 789 | function getBrowser($agent) 790 | { 791 | $outputer = false; 792 | if (preg_match('/MSIE\s([^\s|;]+)/i', $agent, $regs)) { 793 | $outputer = 'IE Browser'; 794 | } else if (preg_match('/FireFox\/([^\s]+)/i', $agent, $regs)) { 795 | $str1 = explode('Firefox/', $regs[0]); 796 | $FireFox_vern = explode('.', $str1[1]); 797 | $outputer = 'Firefox Browser ' . $FireFox_vern[0]; 798 | } else if (preg_match('/Maxthon([\d]*)\/([^\s]+)/i', $agent, $regs)) { 799 | $str1 = explode('Maxthon/', $agent); 800 | $Maxthon_vern = explode('.', $str1[1]); 801 | $outputer = 'Maxthon Browser ' . $Maxthon_vern[0]; 802 | } else if (preg_match('#SE 2([a-zA-Z0-9.]+)#i', $agent, $regs)) { 803 | $outputer = 'Sogo Browser'; 804 | } else if (preg_match('#360([a-zA-Z0-9.]+)#i', $agent, $regs)) { 805 | $outputer = '360 Browser'; 806 | } else if (preg_match('/Edge([\d]*)\/([^\s]+)/i', $agent, $regs)) { 807 | $str1 = explode('Edge/', $regs[0]); 808 | $Edge_vern = explode('.', $str1[1]); 809 | $outputer = 'Edge ' . $Edge_vern[0]; 810 | } else if (preg_match('/EdgiOS([\d]*)\/([^\s]+)/i', $agent, $regs)) { 811 | $str1 = explode('EdgiOS/', $regs[0]); 812 | $outputer = 'Edge'; 813 | } else if (preg_match('/UC/i', $agent)) { 814 | $str1 = explode('rowser/', $agent); 815 | $UCBrowser_vern = explode('.', $str1[1]); 816 | $outputer = 'UC Browser ' . $UCBrowser_vern[0]; 817 | } else if (preg_match('/OPR/i', $agent)) { 818 | $str1 = explode('OPR/', $agent); 819 | $opr_vern = explode('.', $str1[1]); 820 | $outputer = 'Open Browser ' . $opr_vern[0]; 821 | } else if (preg_match('/MicroMesseng/i', $agent, $regs)) { 822 | $outputer = 'Weixin Browser'; 823 | } else if (preg_match('/WeiBo/i', $agent, $regs)) { 824 | $outputer = 'WeiBo Browser'; 825 | } else if (preg_match('/QQ/i', $agent, $regs) || preg_match('/QQ Browser\/([^\s]+)/i', $agent, $regs)) { 826 | $str1 = explode('rowser/', $agent); 827 | $QQ_vern = explode('.', $str1[1]); 828 | $outputer = 'QQ Browser ' . $QQ_vern[0]; 829 | } else if (preg_match('/MQBHD/i', $agent, $regs)) { 830 | $str1 = explode('MQBHD/', $agent); 831 | $QQ_vern = explode('.', $str1[1]); 832 | $outputer = 'QQ Browser ' . $QQ_vern[0]; 833 | } else if (preg_match('/BIDU/i', $agent, $regs)) { 834 | $outputer = 'Baidu Browser'; 835 | } else if (preg_match('/LBBROWSER/i', $agent, $regs)) { 836 | $outputer = 'KS Browser'; 837 | } else if (preg_match('/TheWorld/i', $agent, $regs)) { 838 | $outputer = 'TheWorld Browser'; 839 | } else if (preg_match('/XiaoMi/i', $agent, $regs)) { 840 | $outputer = 'XiaoMi Browser'; 841 | } else if (preg_match('/UBrowser/i', $agent, $regs)) { 842 | $str1 = explode('rowser/', $agent); 843 | $UCBrowser_vern = explode('.', $str1[1]); 844 | $outputer = 'UCBrowser ' . $UCBrowser_vern[0]; 845 | } else if (preg_match('/mailapp/i', $agent, $regs)) { 846 | $outputer = 'Email Browser'; 847 | } else if (preg_match('/2345Explorer/i', $agent, $regs)) { 848 | $outputer = '2345 Browser'; 849 | } else if (preg_match('/Sleipnir/i', $agent, $regs)) { 850 | $outputer = 'Sleipnir Browser'; 851 | } else if (preg_match('/YaBrowser/i', $agent, $regs)) { 852 | $outputer = 'Yandex Browser'; 853 | } else if (preg_match('/Opera[\s|\/]([^\s]+)/i', $agent, $regs)) { 854 | $outputer = 'Opera Browser'; 855 | } else if (preg_match('/MZBrowser/i', $agent, $regs)) { 856 | $outputer = 'MZ Browser'; 857 | } else if (preg_match('/VivoBrowser/i', $agent, $regs)) { 858 | $outputer = 'Vivo Browser'; 859 | } else if (preg_match('/Quark/i', $agent, $regs)) { 860 | $outputer = 'Quark Browser'; 861 | } else if (preg_match('/mixia/i', $agent, $regs)) { 862 | $outputer = 'Mixia Browser'; 863 | } else if (preg_match('/fusion/i', $agent, $regs)) { 864 | $outputer = 'Fusion'; 865 | } else if (preg_match('/CoolMarket/i', $agent, $regs)) { 866 | $outputer = 'CoolMarket Browser'; 867 | } else if (preg_match('/Thunder/i', $agent, $regs)) { 868 | $outputer = 'Thunder Browser'; 869 | } else if (preg_match('/Chrome([\d]*)\/([^\s]+)/i', $agent, $regs)) { 870 | $str1 = explode('Chrome/', $agent); 871 | $chrome_vern = explode('.', $str1[1]); 872 | $outputer = 'Chrome ' . $chrome_vern[0]; 873 | } else if (preg_match('/safari\/([^\s]+)/i', $agent, $regs)) { 874 | $str1 = explode('Version/', $agent); 875 | $safari_vern = explode('.', $str1[1]); 876 | $outputer = 'Safari ' . $safari_vern[0]; 877 | } else { 878 | return false; 879 | } 880 | return $outputer; 881 | } 882 | 883 | /** 获取操作系统信息 agent); ?>*/ 884 | function getOs($agent) 885 | { 886 | $os = false; 887 | 888 | if (preg_match('/win/i', $agent)) { 889 | if (preg_match('/nt 6.0/i', $agent)) { 890 | $os = 'Windows Vista'; 891 | } else if (preg_match('/nt 6.1/i', $agent)) { 892 | $os = 'Windows 7'; 893 | } else if (preg_match('/nt 6.2/i', $agent)) { 894 | $os = 'Windows 8'; 895 | } else if (preg_match('/nt 6.3/i', $agent)) { 896 | $os = 'Windows 8.1'; 897 | } else if (preg_match('/nt 5.1/i', $agent)) { 898 | $os = 'Windows XP'; 899 | } else if (preg_match('/nt 10.0/i', $agent)) { 900 | $os = 'Windows 10'; 901 | } else { 902 | $os = 'Windows'; 903 | } 904 | } else if (preg_match('/android/i', $agent)) { 905 | if (preg_match('/android 9/i', $agent)) { 906 | $os = 'Android P'; 907 | } else if (preg_match('/android 8/i', $agent)) { 908 | $os = 'Android O'; 909 | } else if (preg_match('/android 7/i', $agent)) { 910 | $os = 'Android N'; 911 | } else if (preg_match('/android 6/i', $agent)) { 912 | $os = 'Android M'; 913 | } else if (preg_match('/android 5/i', $agent)) { 914 | $os = 'Android L'; 915 | } else { 916 | $os = 'Android'; 917 | } 918 | } else if (preg_match('/ubuntu/i', $agent)) { 919 | $os = 'Linux'; 920 | } else if (preg_match('/linux/i', $agent)) { 921 | $os = 'Linux'; 922 | } else if (preg_match('/iPhone/i', $agent)) { 923 | $os = 'iPhone'; 924 | } else if (preg_match('/iPad/i', $agent)) { 925 | $os = 'iPad'; 926 | } else if (preg_match('/mac/i', $agent)) { 927 | $os = 'OSX'; 928 | } else if (preg_match('/cros/i', $agent)) { 929 | $os = 'Chrome os'; 930 | } else { 931 | return false; 932 | } 933 | return $os; 934 | } 935 | 936 | /** 937 | * 输出评论回复内容,配合 commentAtContent($coid)一起使用 938 | * coid); ?> 939 | */ 940 | function showCommentContent($coid) 941 | { 942 | $db = Typecho_Db::get(); 943 | $result = $db->fetchRow($db->select('text')->from('table.comments')->where('coid = ? AND status = ?', $coid, 'approved')); 944 | $text = $result['text']; 945 | $atStr = commentAtContent($coid); 946 | $_content = Markdown::convert($text); 947 | //

      948 | if ($atStr !== '') { 949 | $content = substr_replace($_content, $atStr, 0, 3); 950 | } else { 951 | $content = $_content; 952 | } 953 | 954 | echo $content; 955 | } 956 | 957 | /** 958 | * 评论回复加@ 959 | */ 960 | function commentAtContent($coid) 961 | { 962 | $db = Typecho_Db::get(); 963 | $prow = $db->fetchRow($db->select('parent')->from('table.comments')->where('coid = ? AND status = ?', $coid, 'approved')); 964 | $parent = $prow['parent']; 965 | if ($parent != "0") { 966 | $arow = $db->fetchRow($db->select('author')->from('table.comments') 967 | ->where('coid = ? AND status = ?', $parent, 'approved')); 968 | $author = $arow['author']; 969 | $href = '

      @' . $author . ' '; 970 | return $href; 971 | } else { 972 | return ''; 973 | } 974 | } 975 | -------------------------------------------------------------------------------- /header.php: -------------------------------------------------------------------------------- 1 | options->cdn) && $this->options->cdn) { 4 | define('__TYPECHO_THEME_URL__', Typecho_Common::url(__TYPECHO_THEME_DIR__ . '/' . basename(dirname(__FILE__)), $this->options->cdn)); 5 | } 6 | ?> 7 | 8 | 9 | 10 | 11 | 12 | 14 | <?php $this->archiveTitle(array( 15 | 'category' => _t('%s'), 16 | 'search' => _t('%s'), 17 | 'tag' => _t('%s'), 18 | 'author' => _t('%s') 19 | ), '', ' - '); ?><?php $this->options->title(); ?><?php if ($this->is('index') && $this->options->Subtitle != null) { 20 | echo ' - ' . $this->options->Subtitle; 21 | } ?> 22 | 23 | options->qiniu)): ?> 24 | 25 | 26 | options->logoUrl): ?> 27 | 28 | 29 | 30 | 31 | 32 | is('post') || $this->is('page')): ?> 33 | 34 | 35 | options->Logo != null): ?> 36 | 37 | 38 | header(); ?> 39 | is('post')): ?> 40 | 41 | 42 | 43 | 44 |

      45 | 81 |
      82 | is('post')): ?> 83 |
      84 |
      85 |
      86 | 87 |
      88 | 129 |
      130 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 12 | need('header.php'); 14 | $hiddens = ''; 15 | $hidden = ''; 16 | $prev = $page . ($this->_currentPage - 1); 17 | $next = $page . ($this->_currentPage + 1); 18 | if ($this->_currentPage == 0 || $this->_currentPage == 1) { 19 | $hidden = 'hidden'; 20 | $cpage = 1; 21 | } else { 22 | $cpage = $this->_currentPage; 23 | } 24 | if ($this->_currentPage == ceil($this->getTotal() / $this->parameter->pageSize)) { 25 | $hiddens = 'hidden'; 26 | } elseif (ceil($this->getTotal() / $this->parameter->pageSize) == 1) { 27 | $hiddens = 'hidden'; 28 | $hidden = 'hidden'; 29 | } 30 | ?> 31 |
      32 |
      38 |
      39 | is('author')): ?> 40 |
      41 | 头像 43 |
      44 |
      author(); ?>
      45 |
      author->url)['bio'] ?>
      46 |
      47 | author->url)['location'] ?> 48 | 49 | author->uid) ?> 篇文章 50 |
      51 | 89 | is('category')): ?> 90 |
      archiveTitle(array( 91 | 'category' => _t('%s') 92 | ), '', ''); ?>
      93 | getDescription() != null): ?> 94 |
      getDescription())[0] ?>
      96 |
      该分类下有category) ?>篇文章 97 |
      98 | is('index')): ?> 99 |
      options->ititle ?>
      100 |
      我最不喜欢做选择,但我选择了,就一定不后悔。
      101 | 102 |
      103 |
      104 | 106 | 107 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 |
      118 |
      119 | 120 |
      121 |
      122 | next()): ?> 123 |
      124 |
      127 |
      128 |
      129 | 135 |
      143 |
      144 |
      145 |
      146 |
      149 |
      150 | 158 |

      163 | title(); ?> 165 |

      166 |

      171 | fields->previewContent) 173 | $this->fields->previewContent(); 174 | else 175 | $this->excerpt(500, '...'); 176 | ?> 177 |

      178 | 201 |
      202 |
      203 |
      204 | 205 |
      206 | getTotal() / $this->parameter->pageSize) <> 0): ?> 207 |
      208 |
      209 | 221 |
      222 | 223 |
      224 | 225 |
      226 |

      暂无文章

      227 |
      228 | 229 |
      230 | need('footer.php'); ?> 231 | -------------------------------------------------------------------------------- /lib/Comments.php: -------------------------------------------------------------------------------- 1 | '.$os.''; 49 | $browser = null; 50 | //解析浏览器 51 | if (preg_match('#SE 2([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'Sogou browser'; 52 | } elseif (preg_match('#360([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = '360 browser '; 53 | } elseif (preg_match('#Maxthon( |\/)([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'Maxthon '; 54 | } elseif (preg_match('#Edge( |\/)([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'Edge '; 55 | } elseif (preg_match('#MicroMessenger/([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'Wechat '; 56 | } elseif (preg_match('#QQ/([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'QQ Mobile '; 57 | } elseif (preg_match('#Chrome/([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'Chrome '; 58 | } elseif (preg_match('#CriOS/([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'Chrome '; 59 | } elseif (preg_match('#Chromium/([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'Chromium '; 60 | } elseif (preg_match('#Safari/([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'Safari '; 61 | } elseif (preg_match('#opera mini#i', $ua)) { 62 | preg_match('#Opera/([a-zA-Z0-9.]+)#i', $ua, $matches); 63 | $browser = 'Opera Mini ';} elseif (preg_match('#Opera.([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'Opera '; 64 | } elseif (preg_match('#QQBrowser ([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'QQ browser '; 65 | } elseif (preg_match('#UCWEB([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'UCWEB '; 66 | } elseif (preg_match('#MSIE ([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'Internet Explorer '; 67 | } elseif (preg_match('#Trident/([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'Internet Explorer 11'; 68 | } elseif (preg_match('#(Firefox|Phoenix|Firebird|BonEcho|GranParadiso|Minefield|Iceweasel)/([a-zA-Z0-9.]+)#i', $ua, $matches)) {$browser = 'Firefox '; 69 | } else { $browser = 'unknown br'; 70 | } 71 | $htmlTag .= " "; 72 | $htmlTag .= ''.$browser.''; 73 | return $htmlTag; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /lib/Utils.php: -------------------------------------------------------------------------------- 1 | JConfig; 22 | $options = Helper::options(); 23 | $enableLazyload = self::isEnabled('enableLazyload', 'JConfig'); 24 | $enableComments = self::isEnabled('enableComments', 'JConfig'); 25 | $enablePJAX = self::isEnabled('enablePJAX', 'JConfig'); 26 | 27 | $THEME_CONFIG = json_encode((object)array( 28 | "THEME_VERSION" => CREAMy_VERSION, 29 | "SITE_URL" => rtrim($options->siteUrl, "/"), 30 | "THEME_URL" => $options->themeUrl, 31 | "ENABLE_Comments" => $enableComments 32 | )); 33 | 34 | echo "\n"; 35 | } 36 | 37 | /** 38 | * 返回主题设置中某项开关的开启/关闭状态 39 | * 40 | * @param string $item 项目名 41 | * @param string $config 设置名 42 | * 43 | * @return bool 44 | */ 45 | public static function isEnabled($item, $config) 46 | { 47 | $config = Helper::options()->$config; 48 | $status = !empty($config) && in_array($item, $config) ? true : false; 49 | return $status; 50 | } 51 | 52 | /** 53 | * 获取背景图片 54 | * 55 | * @return void 56 | */ 57 | public static function getBackground() 58 | { 59 | $options = Helper::options(); 60 | if (!null == $options->qiniu) { 61 | $qurl = str_replace($options->siteUrl, $options->qiniu . '/', $options->themeUrl); 62 | } else { 63 | $qurl = $options->themeUrl; 64 | } 65 | if ($options->bgUrl) { 66 | echo $options->bgUrl; 67 | } else { 68 | echo $qurl . '/assets/img/hero-background.jpg'; 69 | } 70 | } 71 | 72 | /** 73 | * 获取默认缩略图 74 | */ 75 | public static function getThumbnail() 76 | { 77 | /*$options = Helper::options(); 78 | if (!null == $options->qiniu) { 79 | $qurl = str_replace($options->siteUrl, $options->qiniu . '/', $options->themeUrl); 80 | } else { 81 | $qurl = $options->themeUrl; 82 | } 83 | return $qurl . '/assets/img/post.jpg';*/ 84 | return 'https://ae01.alicdn.com/kf/H54ab5ecac0e4422aa32abbde20d98842E.png'; 85 | } 86 | 87 | /** 88 | * 获取内容 89 | */ 90 | public static function getContent($content) 91 | { 92 | $options = Helper::options(); 93 | if ($options->qiniu != null) { 94 | $site = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST']; 95 | return str_replace($site, $options->qiniu, $content); 96 | } else { 97 | return $content; 98 | } 99 | } 100 | 101 | /** 102 | * 获取分类文章数量 103 | */ 104 | public static function getCnums($name) 105 | { 106 | $db = Typecho_Db::get(); 107 | $cx = $db->fetchRow($db->select()->from('table.metas')->where('table.metas.type = ?', 'category')->where('table.metas.slug = ?', $name))['count']; 108 | if ($cx <= 0) { 109 | return 0; 110 | } 111 | return $cx; 112 | } 113 | 114 | /** 115 | * 获取评论者GRAVATAR头像 116 | */ 117 | public static function gGravatar($author) 118 | { 119 | $db = Typecho_Db::get(); 120 | $cx = $db->fetchRow($db->select()->from('table.comments')->where('table.comments.author = ?', $author))['mail']; 121 | if (defined('__TYPECHO_GRAVATAR_PREFIX__')) { 122 | $url = __TYPECHO_GRAVATAR_PREFIX__; 123 | } else { 124 | if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off') { 125 | $http_type = 'https'; 126 | } elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { 127 | $http_type = 'https'; 128 | } elseif (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off') { 129 | $http_type = 'https'; 130 | } 131 | $http_type = 'http'; 132 | if ($http_type == 'https') { 133 | $url = 'https://secure.gravatar.com'; 134 | } else { 135 | $url = 'http://www.gravatar.com'; 136 | } 137 | $url .= '/avatar/'; 138 | } 139 | 140 | if (!empty($cx)) { 141 | $url .= md5(strtolower(trim($cx))); 142 | } 143 | 144 | $url .= '?s=60'; 145 | $url .= '&r=G'; 146 | return $url; 147 | } 148 | 149 | public static function getCategoryCount($content) 150 | { 151 | $tmp = explode('$', $content); 152 | return $tmp; 153 | } 154 | 155 | public static function getSkey($key) 156 | { 157 | $tmp = explode('/search/', $key); 158 | $tmp = str_replace('/', '', $tmp); 159 | return $tmp[1]; 160 | } 161 | 162 | public static function getCagegoryName($slug) 163 | { 164 | $db = Typecho_Db::get(); 165 | $name = $db->fetchRow($db->select()->from('table.metas')->where('table.metas.type = ?', 'category')->where('table.metas.slug = ?', $slug))['name']; 166 | return $name; 167 | } 168 | 169 | public static function getAuthorPosts($id) 170 | { 171 | $db = Typecho_Db::get(); 172 | $postnum = $db->fetchRow($db->select(array('COUNT(authorId)' => 'allpostnum'))->from('table.contents')->where('table.contents.authorId=?', $id)->where('table.contents.type=?', 'post')); 173 | $postnum = $postnum['allpostnum']; 174 | return $postnum; 175 | } 176 | 177 | public static function getAuthor($data) 178 | { 179 | $tmp = explode('$', $data); 180 | $arr['site'] = $tmp[0]; 181 | $arr['bio'] = $tmp[1]; 182 | $arr['location'] = $tmp[2]; 183 | return $arr; 184 | } 185 | 186 | public static function getGravatar($email, $s = 96, $d = 'mp', $r = 'g', $img = false, $atts = array()) 187 | { 188 | $url = '//cdn.v2ex.com/gravatar/'; 189 | $url .= md5(strtolower(trim($email))); 190 | $url .= "?s=$s&d=$d&r=$r"; 191 | if ($img) { 192 | $url = ' $val) 194 | $url .= ' ' . $key . '="' . $val . '"'; 195 | $url .= ' />'; 196 | } 197 | return $url; 198 | } 199 | 200 | } 201 | -------------------------------------------------------------------------------- /page-about.php: -------------------------------------------------------------------------------- 1 | need('header.php'); 11 | ?> 12 |
      13 |
      15 |
      16 |
      title; ?>
      17 |
      18 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
      32 |
      33 |
      34 |
      35 |
      36 |
      37 |
      38 | alert('Hello World!') 39 |
      40 |
      41 |
      42 | 43 |
      44 |

      45 | const aboutMe = { 46 |
      47 | name: 'Leslie Lin', 48 |
      49 | email: 'i@iobiji.com', 50 |
      51 | position: 'Web Front-End Developer', 52 |
      53 | website: 'https://iobiji.com' 54 |
      }; 55 |

      56 |
      57 |
      58 |
      59 |
      60 |
      61 |
      62 |
      63 | content) ?> 64 |
      65 |
      66 |
      67 |
      68 | 81 | need('footer.php'); ?> 82 | -------------------------------------------------------------------------------- /page-archive.php: -------------------------------------------------------------------------------- 1 | need('header.php'); 11 | ?> 12 | to($stat); ?> 13 | 14 |
      15 |
      17 |
      18 |
      title; ?>
      19 |
      20 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
      34 |
      35 |
      36 |
      37 |
      38 |
      40 |
      41 |
      截至 共写了publishedPostsNum() ?>文章
      42 |
        43 | widget('Widget_Contents_Post_Recent', 'pageSize=10000')->parse('
      • {title}
      • '); ?> 44 |
      45 |
      46 |
      47 |
      48 |
      49 | 50 | need('footer.php'); ?> 51 | -------------------------------------------------------------------------------- /page-links.php: -------------------------------------------------------------------------------- 1 | need('header.php'); 11 | ?> 12 | 13 |
      14 |
      16 |
      17 |
      title; ?>
      18 |
      19 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
      33 |
      34 |
      35 |
      36 |
      37 |
      39 | content) ?> 40 |
      41 |
      42 |
      43 | 44 | need('footer.php'); ?> 45 | -------------------------------------------------------------------------------- /page.php: -------------------------------------------------------------------------------- 1 | 2 | need('header.php'); ?> 3 |
      4 |
      6 |
      7 |
      title; ?>
      8 |
      9 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
      23 |
      24 | 25 |
      26 |
      27 |
      28 |
      29 | content); ?> 30 |
      31 |
      32 |
      33 | 46 | need('footer.php'); ?> 47 | -------------------------------------------------------------------------------- /post.php: -------------------------------------------------------------------------------- 1 | 2 | need('header.php'); ?> 3 |
      4 |
      6 |
      7 |
      title; ?>
      8 |
      author(); ?> 9 | / created) ?> 10 | / / 阅读量
      11 |
      12 |
      13 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
      27 |
      28 | 29 |
      30 |
      31 | 40 |
      41 |
      42 | content); ?> 43 |
      44 |
      45 | 47 |
      48 |
      49 |
      50 | 61 | 72 |
      73 |
      74 |
      75 | options->alipay != null): ?> 76 |
      77 |
      78 | 支付宝捐赠 79 |
      请使用支付宝扫一扫进行捐赠
      80 |
      81 |
      82 | 83 | options->wpay != null): ?> 84 |
      85 |
      86 | 微信捐赠 87 |
      请使用微信扫一扫进行赞赏
      88 |
      89 |
      90 | 91 |
      92 |
      93 |
      94 |
      95 |
        96 |
      • 97 | 文章作者: 98 | author(); ?> 99 |
      • 100 |
      • 101 | 文章链接: 102 | permalink; ?> 103 |
      • 104 |
      • 105 | 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 107 | 许可协议。转载请注明出处! 108 |
      • 109 |
      110 | 152 | 153 | 258 | 259 |
      260 | 261 | 262 | need('comments.php'); ?> 263 | 264 |
      265 |
      266 | 267 |
      268 |
      269 |
      270 | need('footer.php'); ?> 271 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unsafe-ptr/Spring/23d1f9522acf20328441432340609cef3cc74082/screenshot.png -------------------------------------------------------------------------------- /search.php: -------------------------------------------------------------------------------- 1 | 12 | need('header.php'); 14 | $hiddens = ''; 15 | $hidden = ''; 16 | $prev = $this->_currentPage - 1; 17 | $next = $this->_currentPage + 1; 18 | if ($this->_currentPage == 0 || $this->_currentPage == 1) { 19 | $hidden = 'hidden'; 20 | $cpage = 1; 21 | } else { 22 | $cpage = $this->_currentPage; 23 | } 24 | if ($this->_currentPage == ceil($this->getTotal() / $this->parameter->pageSize)) { 25 | $hiddens = 'hidden'; 26 | } elseif (ceil($this->getTotal() / $this->parameter->pageSize) == 1) { 27 | $hiddens = 'hidden'; 28 | $hidden = 'hidden'; 29 | } 30 | ?> 31 |
      32 |
      38 |
      39 | is('author')): ?> 40 |
      41 | 头像 43 |
      44 |
      author(); ?>
      45 |
      author->url)['bio'] ?>
      46 |
      47 | author->url)['location'] ?> 48 | 49 | author->uid) ?> 篇文章 50 |
      51 | 89 | is('category')): ?> 90 |
      archiveTitle(array( 91 | 'category' => _t('%s') 92 | ), '', ''); ?>
      93 | getDescription() != null): ?> 94 |
      getDescription())[0] ?>
      96 |
      该分类下有category) ?>篇文章 97 |
      98 | is('index')): ?> 99 |
      options->ititle ?>
      100 |
      我最不喜欢做选择,但我选择了,就一定不后悔。
      101 | 102 |
      103 |
      104 | 106 | 107 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 |
      118 |
      119 | 120 |
      121 |
      122 | next()): ?> 123 |
      124 |
      127 |
      128 |
      129 | 135 |
      143 |
      144 |
      145 |
      146 |
      149 |
      150 | 158 |

      163 | title(); ?> 165 |

      166 |

      171 | fields->previewContent) 173 | $this->fields->previewContent(); 174 | else 175 | $this->excerpt(500, '...'); 176 | ?> 177 |

      178 | 201 |
      202 |
      203 |
      204 | 205 |
      206 | getTotal() / $this->parameter->pageSize) <> 0): ?> 207 |
      208 |
      209 | 221 |
      222 | 223 |
      224 | 225 |
      226 |

      搜索不到关键字为的文章

      227 |
      228 | 229 |
      230 | need('footer.php'); ?> 231 | --------------------------------------------------------------------------------