feat(*): cheers for the v2 pre-release

This commit is contained in:
ppoffice 2018-10-26 00:51:10 -04:00
commit 001feaa8ec
292 changed files with 3541 additions and 19374 deletions

View File

@ -1,11 +1,4 @@
Please make sure these boxes are checked before submitting your issue. Thank you!
Please make sure you took care of the following things before you submit this issue. Thank you!
- [ ] I have setuped and configurated the blog according to [Hexo official documentation](https://hexo.io/);
- [ ] I have read the [Theme Wiki](https://github.com/ppoffice/hexo-theme-icarus/wiki) carefully and created my own configuration file(_config.yml);
- [ ] I have looked up the [Issues](https://github.com/ppoffice/hexo-theme-icarus/issues) and found no duplicate issues.
请在发布新Issue之前确保你已经进行了如下工作谢谢
- [ ] 我已经按照[Hexo官方文档](https://hexo.io/)中的步骤安装与配置了Hexo
- [ ] 我已经仔细地阅读了[主题Wiki](https://github.com/ppoffice/hexo-theme-icarus/wiki)并创建了自己的配置文件(_config.yml)
- [ ] 我已经搜索了[Issues](https://github.com/ppoffice/hexo-theme-icarus/issues),并且没有找到类似的问题。
- [ ] I have set up and configured my blog according to [Hexo documentation](https://hexo.io/) and [Icarus Documentation](https://github.com/ppoffice/hexo-theme-icarus/wiki);
- [ ] I have looked up the [Github Issues](https://github.com/ppoffice/hexo-theme-icarus/issues) and found no solutions to my problems.

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015 ZHANG Ruipeng
Copyright (c) 2015 PPOffice
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

144
README.md
View File

@ -1,62 +1,134 @@
# Icarus
<p align="center" class="has-mb-6">
<img class="not-gallery-item" style="height:48px" src="http://ppoffice.github.io/hexo-theme-icarus/images/logo.svg">
<br> A simple, delicate, and modern theme for the static site generator Hexo.
<br>
<a href="http://ppoffice.github.io/hexo-theme-icarus/">Preview</a> |
<a href="http://ppoffice.github.io/hexo-theme-icarus/categories/">Documentation</a> |
<a href="https://github.com/ppoffice/hexo-theme-icarus/archive/master.zip">Download</a>
<br>
### The blog theme you may fall in love with, coming to Hexo. [Preview](http://ppoffice.github.io/hexo-theme-icarus/)
![](http://ppoffice.github.io/hexo-theme-icarus/gallery/preview.png "")
[![GitHub release](https://img.shields.io/github/release/qubyte/rubidium.svg)](https://github.com/ppoffice/hexo-theme-icarus)
</p>
#### [View Documentation](https://github.com/ppoffice/hexo-theme-icarus/wiki)
:star: It is strongly recommended that you read the docs before using Icarus.
![Icarus](http://ppoffice.github.io/hexo-theme-icarus/gallery/preview.png "Icarus Preview")
## Features
### :cd: Installation
### Profile Sidebar
Download & extract or `git clone` Icarus from GitHub to your blog's theme folder, and that's it!
A nice place to show yourself. You can add your own information in your site's `_config.yml`
```shell
git clone https://github.com/ppoffice/hexo-theme-icarus.git themes/icarus
```
![](http://ppoffice.github.io/hexo-theme-icarus/gallery/profile.png "")
Once started, Icarus will remind you of any missing dependencies and configuration files.
### Self-hosted Insite Search Engine
With the help of [Insight Search](https://github.com/ppoffice/hexo-theme-icarus/wiki/Search#insight-search), you can search anything inside your site without any third-party plugin.
### :gift: Features
![](http://ppoffice.github.io/hexo-theme-icarus/gallery/insight-search.png "")
**Extensive Plugin Support**
### Custom Comment Services
Icarus supports several comment services, give you better choices to communicate with your readers.
Icarus includes plentiful search, comment, sharing and other plugins out of the box. You can choose any of them to enrich your
blog experience, or build your own plugin easily referring to the existing Icarus plugins.
![](http://ppoffice.github.io/hexo-theme-icarus/gallery/custom-comments.png "")
Comment plugins
### Post Banner & Thumbnail
- [Changyan](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Comment/changyan-comment-plugin/)
- [Disqus](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Comment/disqus-comment-plugin/)
- [Facebook](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Comment/facebook-comment-plugin/)
- [Gitment](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Comment/gitment-comment-plugin/)
- [Isso](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Comment/isso-comment-plugin/)
- [LiveRe](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Comment/livere-comment-plugin/)
- [Valine](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Comment/valine-comment-plugin/)
Thanks to [atika](https://github.com/atika), you can now [add thumbnails or banners](https://github.com/ppoffice/hexo-theme-icarus/wiki/Theme#thumbnail) to every post to create better reading experience.
Search plugins
### Responsive Layout
- [Insight Search](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Search/insight-search-plugin/)
- [Google Custom Search Engine](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Search/google-cse-plugin/)
- [Baidu Site Search](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Search/baidu-search-plugin/)
Icarus knows on what screen size you are browsering the website, and reorganize the layout to fit your device.
Share plugins
![](http://ppoffice.github.io/hexo-theme-icarus/gallery/responsive.jpg "")
- [AddThis](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Share/addthis-share-plugin/)
- [AddToAny](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Share/addtoany-share-plugin/)
- [Baidu Share](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Share/baidu-share-plugin/)
- [Share.js](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Share/sharejs-share-plugin/)
- [ShareThis](http://ppoffice.github.io/hexo-theme-icarus/Plugins/Share/sharethis-share-plugin/)
### Custom Categories & Tags Pages
Other plugins
Get your categories and tags listed in single pages to make your blog more methodic.
- [Hexo Tag Plugin](http://ppoffice.github.io/hexo-theme-icarus/Configuration/Posts/hexo-built-in-tag-helpers/)
- [lightGallery & Justified Gallery](http://ppoffice.github.io/hexo-theme-icarus/Plugins/General/gallery-plugin/)
- [MathJax](http://ppoffice.github.io/hexo-theme-icarus/Plugins/General/mathjax-plugin/)
- [Site Analytics](http://ppoffice.github.io/hexo-theme-icarus/Plugins/General/site-analytics-plugin/)
### lightgallery
**Rich Code Highlight Theme Choices**
Icarus uses [lightgallery.js](https://sachinchoolur.github.io/lightgallery.js/) to showcase your photos. Just enable it in your configuration, and that's all!
Icarus directly import code highlight themes from the [highlight.js](https://highlightjs.org/) package, and makes more than
70 highlight themes available to you.
![](http://ppoffice.github.io/hexo-theme-icarus/gallery/lightgallery.jpg "")
<div class="columns is-multiline is-mobile">
<div class="column is-half-mobile"><img src="http://ppoffice.github.io/hexo-theme-icarus/gallery/code-highlight/atom-one-light.png"></div>
<div class="column is-half-mobile"><img src="http://ppoffice.github.io/hexo-theme-icarus/gallery/code-highlight/monokai.png"></div>
<div class="column is-half-mobile"><img src="http://ppoffice.github.io/hexo-theme-icarus/gallery/code-highlight/androidstudio.png"></div>
</div>
### Justified Gallery
**Elastic Theme Configuration**
You can also use [justifiedgallery.js](http://miromannino.github.io/Justified-Gallery/) to display a photo grid within your posts. Just enable it in your configuration, and place your photos in a div with the class .justified-gallery
In addition to the minimalistic and easy-to-understand configuration design, Icarus allows you to set configurations on a
per-page basis with the ability to merge and override partial configurations.
### Sidebar
<div>
<table>
<tr>
<th>_config.yml</th>
<th>post.md</th>
</tr>
<tr>
<td>
<pre>menu:
Archives: /archives
Categories: /categories
Tags: /tags
About: /about</pre>
</td>
<td>
<pre>title: A Simple Post
menu:
Go Home: /index.html
---
# Here is some simple markdown.</pre>
</td>
</tr>
<tr>
<td><img height="40" src="http://ppoffice.github.io/hexo-theme-icarus/gallery/navbar/main-config.png"></td>
<td><img height="40" src="http://ppoffice.github.io/hexo-theme-icarus/gallery/navbar/post-config.png"></td>
</tr>
</table>
</div>
Icarus provides 6 built-in widgets:
**Responsive Layout**
- recent_posts
- category
- archives
- tag
- tagcloud
- links
No matter what modern browsering device your audiences are using, they can always get the best experience because Icarus's responsive
layout across multiple viewpoints.
All of them are enabled by default. You can edit them in `widget` setting.
![Responsive Layout](http://ppoffice.github.io/hexo-theme-icarus/gallery/responsive.png)
### :hammer: Development
This project is built with
- Hexo 3.7.1
- Ejs
- Stylus
- Bulma 0.7.2
Please refer to the documentation for Icarus implementation details.
### :tada: Contribute
:electric_plug: Write a plugin |
:triangular_flag_on_post: <a href="https://github.com/ppoffice/hexo-theme-icarus/issues/new">Report a bug</a> |
:earth_asia: <a href="https://github.com/ppoffice/hexo-theme-icarus/tree/master/languages">Add a translation</a>
### :memo: License
This project is licensed under the MIT License - see the [LICENSE](https://github.com/ppoffice/hexo-theme-icarus/blob/master/LICENSE) file for details.

View File

@ -1,98 +0,0 @@
# Menus
menu:
Home: .
Archives: archives
Categories: categories
Tags: tags
About: about
# Customize
customize:
logo:
enabled: true
width: 40
height: 40
url: images/logo.png
profile:
enabled: true # Whether to show profile bar
fixed: true
avatar: css/images/avatar.png
gravatar: # Gravatar email address, if you enable Gravatar, your avatar config will be overriden
author: PPOffice
author_title: Web Developer & Designer
location: Harbin, China
follow: https://github.com/ppoffice/
highlight: monokai
sidebar: right # sidebar position, options: left, right or leave it empty
thumbnail: true # enable posts thumbnail, options: true, false
favicon: # path to favicon
social_links:
github: http://github.com/ppoffice/hexo-theme-icarus
twitter: /
facebook: /
dribbble: /
rss: /
social_link_tooltip: true # enable the social link tooltip, options: true, false
# Widgets
widgets:
- recent_posts
- category
- archive
- tag
- tagcloud
- links
# Search
search:
insight: true # you need to install `hexo-generator-json-content` before using Insight Search
swiftype: # enter swiftype install key here
baidu: false # you need to disable other search engines to use Baidu search, options: true, false
# Comment
comment:
disqus: # enter disqus shortname here
duoshuo: # enter duoshuo shortname here
youyan: # enter youyan uid here
facebook: # enter true to enable
isso: # enter the domain name of your own comment isso server eg. comments.example.com
changyan: # please fill in `appid` and `conf` to enable
appid:
conf:
gitment:
owner: #your github ID
repo: #the repo to store comments
#Register an OAuth application, and you will get a client ID and a client secret.
client_id: #your client ID
client_secret: #your client secret
livere: # enter livere uid here
valine: # Valine Comment System https://github.com/xCss/Valine
on: # enter true to enable
appId: # enter the leancloud application appId here
appKey: # enter the leancloud application appKey here
notify: # enter true to enable <Mail notifier> https://github.com/xCss/Valine/wiki/Valine-%E8%AF%84%E8%AE%BA%E7%B3%BB%E7%BB%9F%E4%B8%AD%E7%9A%84%E9%82%AE%E4%BB%B6%E6%8F%90%E9%86%92%E8%AE%BE%E7%BD%AE
verify: # enter true to enable <Validation code>
placeholder: Just Do It # enter the comment box placeholder
# Share
share: default # options: jiathis, bdshare, addtoany, default
# Plugins
plugins:
lightgallery: true # options: true, false
justifiedgallery: true # options: true, false
google_analytics: # enter the tracking ID for your Google Analytics
google_site_verification: # enter Google site verification code
baidu_analytics: # enter Baidu Analytics hash key
mathjax: false # options: true, false
# Miscellaneous
miscellaneous:
open_graph: # see http://ogp.me
fb_app_id:
fb_admins:
twitter_id:
google_plus:
links:
Hexo: http://hexo.io

View File

@ -1,4 +0,0 @@
title: "About"
layout: "page"
---

View File

@ -1,3 +0,0 @@
title: "Categories"
layout: "categories"
---

View File

@ -1,3 +0,0 @@
title: "Tags"
layout: "tags"
---

View File

@ -0,0 +1,84 @@
const yaml = require('js-yaml');
const Type = require('js-yaml/lib/js-yaml/type');
const Schema = require('js-yaml/lib/js-yaml/schema');
const { is, descriptors } = require('./utils');
const { doc, type, requires, defaultValue } = descriptors;
const UNDEFINED = Symbol('undefined');
// output null as empty in yaml
const YAML_SCHEMA = new Schema({
include: [
require('js-yaml/lib/js-yaml/schema/default_full')
],
implicit: [
new Type('tag:yaml.org,2002:null', {
kind: 'scalar',
resolve(data) {
if (data === null) {
return true;
}
const max = data.length;
return (max === 1 && data === '~') ||
(max === 4 && (data === 'null' || data === 'Null' || data === 'NULL'));
},
construct: () => null,
predicate: object => object === null,
represent: {
empty: function () { return ''; }
},
defaultStyle: 'empty'
})
]
});
function generate(spec, parentConfig = null) {
if (!is.spec(spec)) {
return UNDEFINED;
}
if (spec.hasOwnProperty(requires) && !spec[requires](parentConfig)) {
return UNDEFINED;
}
if (spec.hasOwnProperty(defaultValue)) {
return spec[defaultValue];
}
const types = is.array(spec[type]) ? spec[type] : [spec[type]];
if (types.includes('object')) {
let defaults = UNDEFINED;
for (let key in spec) {
if (key === '*') {
continue;
}
const value = generate(spec[key], defaults);
if (value !== UNDEFINED) {
if (defaults === UNDEFINED) {
defaults = {};
}
if (spec[key].hasOwnProperty(doc)) {
defaults['#' + key] = spec[key][doc];
}
defaults[key] = value;
}
}
return defaults;
} else if (types.includes('array') && spec.hasOwnProperty('*')) {
return [generate(spec['*'], {})];
}
return UNDEFINED;
}
class ConfigGenerator {
constructor(spec) {
this.spec = spec;
}
generate() {
return yaml.safeDump(generate(this.spec), {
indent: 4,
lineWidth: 1024,
schema: YAML_SCHEMA
}).replace(/^(\s*)\'#.*?\':\s*\'*(.*?)\'*$/mg, '$1# $2'); // make comment lines
}
}
module.exports = ConfigGenerator;

View File

@ -0,0 +1,132 @@
const { is, descriptors } = require('./utils');
const { type, required, requires, format, defaultValue } = descriptors;
const {
InvalidSpecError,
MissingRequiredError,
TypeMismatchError,
FormatMismatchError,
VersionMalformedError,
VersionNotFoundError,
VersionMismatchError } = require('./utils').errors;
function isRequiresSatisfied(spec, config) {
try {
if (!spec.hasOwnProperty(requires) || spec[requires](config) === true) {
return true;
}
} catch (e) { }
return false;
}
function getConfigType(spec, config) {
const specTypes = is.array(spec[type]) ? spec[type] : [spec[type]];
for (let specType of specTypes) {
if (is[specType](config)) {
return specType;
}
}
return null;
}
function hasFormat(spec, config) {
if (!spec.hasOwnProperty(format)) {
return true;
}
return spec[format].test(config);
}
function validate(spec, config, parentConfig, path) {
if (!is.spec(spec)) {
throw new InvalidSpecError(spec, path);
}
if (!isRequiresSatisfied(spec, parentConfig)) {
return;
}
if (is.undefined(config) || is.null(config)) {
if (spec[required] === true) {
throw new MissingRequiredError(spec, path);
}
return;
}
const type = getConfigType(spec, config);
if (type === null) {
throw new TypeMismatchError(spec, path, config);
}
if (type === 'string') {
if (!hasFormat(spec, config)) {
throw new FormatMismatchError(spec, path, config);
}
} else if (type === 'array' && spec.hasOwnProperty('*')) {
config.forEach((child, i) => validate(spec['*'], child, config, path.concat(`[${i}]`)));
} else if (type === 'object') {
for (let key in spec) {
if (key === '*') {
Object.keys(config).forEach(k => validate(spec['*'], config[k], config, path.concat(k)));
} else {
validate(spec[key], config[key], config, path.concat(key));
}
}
}
}
function formatVersion(ver) {
const m = /^(\d)+\.(\d)+\.(\d)+(?:-([0-9A-Za-z-]+))*$/.exec(ver);
if (m === null) {
throw new VersionMalformedError(ver);
}
return {
major: m[1],
minor: m[2],
patch: m[3],
identifier: m.length > 4 ? m[4] : null
};
}
function compareVersion(ver1, ver2) {
for (let section of ['major', 'minor', 'patch']) {
if (ver1[section] !== ver2[section]) {
return Math.sign(ver1[section] - ver2[section]);
}
}
const id1 = ver1.hasOwnProperty('identifier') ? ver1.identifier : null;
const id2 = ver2.hasOwnProperty('identifier') ? ver2.identifier : null;
if (id1 === id2) {
return 0;
}
if (id1 === null) {
return 1;
}
if (id2 === null) {
return -1;
}
return id1.localeCompare(id2);
}
function isBreakingChange(base, ver) {
return base.major !== ver.major;
}
function checkVersion(spec, config) {
if (!config.hasOwnProperty('version')) {
throw new VersionNotFoundError();
}
const configVersion = formatVersion(config.version);
const specVersion = formatVersion(spec.version[defaultValue]);
if (isBreakingChange(specVersion, configVersion)) {
throw new VersionMismatchError(spec.version[defaultValue], config.version, compareVersion(specVersion, configVersion) > 0);
}
}
class ConfigValidator {
constructor(spec) {
this.spec = spec;
}
validate(config) {
checkVersion(this.spec, config);
validate(this.spec, config, null, []);
}
}
module.exports = ConfigValidator;

148
includes/common/utils.js Normal file
View File

@ -0,0 +1,148 @@
const doc = Symbol('@doc');
const type = Symbol('@type');
const format = Symbol('@format');
const required = Symbol('@required');
const requires = Symbol('@requires');
const defaultValue = Symbol('@default');
const descriptors = {
doc,
type,
format,
requires,
required,
defaultValue
};
const is = (() => ({
string(value) {
return typeof (value) === 'string';
},
array(value) {
return Array.isArray(value);
},
boolean(value) {
return typeof (value) === 'boolean';
},
object(value) {
return typeof (value) === 'object' && value.constructor == Object;
},
function(value) {
return typeof (value) === 'function';
},
regexp(value) {
return value instanceof RegExp;
},
undefined(value) {
return typeof (value) === 'undefined';
},
null(value) {
return value === null;
},
spec(value) {
if (!value.hasOwnProperty(type)) {
return false;
}
if (!is.string(value[type]) && !is.array(value[type])) {
return false;
}
if (value.hasOwnProperty(doc) && !is.string(value[doc])) {
return false;
}
if (value.hasOwnProperty(required) && !is.boolean(value[required])) {
return false;
}
if (value.hasOwnProperty(requires) && !is.function(value[requires])) {
return false;
}
if (value.hasOwnProperty(format) && !is.regexp(value[format])) {
return false;
}
return true;
}
}))();
class ConfigError extends Error {
constructor(spec, path) {
super();
this.spec = spec;
this.path = path;
}
}
class InvalidSpecError extends ConfigError {
constructor(spec, path) {
super(spec, path);
this.message = `The specification '${path.join('.')}' is invalid.`;
}
}
class MissingRequiredError extends ConfigError {
constructor(spec, path) {
super(spec, path);
this.message = `Configuration file do not have the required '${path.join('.')}' field.`;
}
}
class TypeMismatchError extends ConfigError {
constructor(spec, path, config) {
super(spec, path);
this.config = config;
this.message = `Configuration '${path.join('.')}' is not one of the '${spec[type]}' type.`;
}
}
class FormatMismatchError extends ConfigError {
constructor(spec, path, config) {
super(spec, path);
this.config = config;
this.message = `Configuration '${path.join('.')}' do not match the format '${spec[format]}'.`;
}
}
class VersionError extends Error {
}
class VersionNotFoundError extends VersionError {
constructor() {
super(`Version number is not found in the configuration file.`);
}
}
class VersionMalformedError extends VersionError {
constructor(version) {
super(`Version number ${version} is malformed.`);
this.version = version;
}
}
class VersionMismatchError extends VersionError {
constructor(specVersion, configVersion, isConfigVersionSmaller) {
super();
this.specVersion = specVersion;
this.configVersion = configVersion;
if (isConfigVersionSmaller) {
this.message = `The configuration version ${configVersion} is far behind the specification version ${specVersion}.`;
} else {
this.message = `The configuration version ${configVersion} is way ahead of the specification version ${specVersion}.`;
}
}
}
const errors = {
ConfigError,
InvalidSpecError,
MissingRequiredError,
TypeMismatchError,
FormatMismatchError,
VersionError,
VersionMalformedError,
VersionNotFoundError,
VersionMismatchError
}
module.exports = {
is,
descriptors,
errors
};

View File

@ -0,0 +1,25 @@
const cheerio = require('cheerio');
module.exports = function (hexo) {
function patchCodeHighlight(content) {
const $ = cheerio.load(content, { decodeEntities: false });
$('figure.highlight').addClass('hljs');
$('figure.highlight .code .line span').each(function () {
const classes = $(this).attr('class').split(' ');
if (classes.length === 1) {
$(this).addClass('hljs-' + classes[0]);
$(this).removeClass(classes[0]);
}
});
return $.html();
}
/**
* Add .hljs class name to the code blocks and code elements
*/
hexo.extend.filter.register('after_post_render', function (data) {
data.content = data.content ? patchCodeHighlight(data.content) : data.content;
data.excerpt = data.excerpt ? patchCodeHighlight(data.excerpt) : data.excerpt;
return data;
});
}

View File

@ -0,0 +1,14 @@
/**
* Category list page generator
*/
module.exports = function (hexo) {
hexo.extend.generator.register('categories', function (locals) {
return {
path: 'categories/',
layout: ['categories'],
data: Object.assign({}, locals, {
__categories: true
})
};
});
}

View File

@ -0,0 +1,34 @@
const pagination = require('hexo-pagination');
module.exports = function (hexo) {
// ATTENTION: This will override the default category generator!
hexo.extend.generator.register('category', function(locals) {
const config = this.config;
const perPage = config.category_generator.per_page;
const paginationDir = config.pagination_dir || 'page';
function findParent(category) {
let parents = [];
if (category && category.hasOwnProperty('parent')) {
const parent = locals.categories.filter(cat => cat._id === category.parent).first();
parents = [parent].concat(findParent(parent));
}
return parents;
}
return locals.categories.reduce(function(result, category){
const posts = category.posts.sort('-date');
const data = pagination(category.path, posts, {
perPage: perPage,
layout: ['category', 'archive', 'index'],
format: paginationDir + '/%d/',
data: {
category: category.name,
parents: findParent(category)
}
});
return result.concat(data);
}, []);
});
}

View File

@ -0,0 +1,43 @@
const util = require('hexo-util');
/**
* Insight search content.json generator.
*/
module.exports = function (hexo) {
hexo.extend.generator.register('insight', function (locals) {
const url_for = hexo.extend.helper.get('url_for').bind(this);
function minify(str) {
return util.stripHTML(str).trim().replace(/\n/g, ' ').replace(/\s+/g, ' ')
.replace(/&#x([\da-fA-F]+);/g, function (match, hex) {
return String.fromCharCode(parseInt(hex, 16));
})
.replace(/&#([\d]+);/g, function (match, dec) {
return String.fromCharCode(dec);
});
}
function postMapper(post) {
return {
title: post.title,
text: minify(post.content),
link: url_for(post.path)
}
}
function tagMapper(tag) {
return {
name: tag.name,
slug: tag.slug,
link: url_for(tag.path)
}
}
const site = {
pages: locals.pages.map(postMapper),
posts: locals.posts.map(postMapper),
tags: locals.tags.map(tagMapper),
categories: locals.categories.map(tagMapper)
};
return {
path: '/content.json',
data: JSON.stringify(site)
};
});
}

View File

@ -0,0 +1,14 @@
/**
* Tag list page generator
*/
module.exports = function (hexo) {
hexo.extend.generator.register('tags', function (locals) {
return {
path: 'tags/',
layout: ['tags'],
data: Object.assign({}, locals, {
__tags: true
})
};
});
}

55
includes/helpers/cdn.js Normal file
View File

@ -0,0 +1,55 @@
/**
* CDN static file resolvers.
*
* @example
* <%- cdn(package, version, filename) %>
* <%- fontcdn(fontName) %>
* <%- iconcdn() %>
*/
const cdn_providers = {
cdnjs: 'https://cdnjs.cloudflare.com/ajax/libs/${ package }/${ version }/${ filename }',
jsdelivr: 'https://cdn.jsdelivr.net/npm/${ package }@${ version }/${ filename }',
jsdelivr_github: 'https://cdn.jsdelivr.net/gh/user/${ package }@${ version }/${ filename }',
unpkg: 'https://unpkg.com/${ package }@${ version }/${ filename }'
};
const font_providers = {
google: 'https://fonts.googleapis.com/css?family=${ fontname }'
};
const icon_providers = {
fontawesome: 'https://use.fontawesome.com/releases/v5.4.1/css/all.css',
material: 'https://fonts.googleapis.com/icon?family=Material+Icons'
};
module.exports = function (hexo) {
hexo.extend.helper.register('cdn', function (package, version, filename) {
let provider = hexo.extend.helper.get('get_config').bind(this)('providers.cdn');
if (provider !== null && cdn_providers.hasOwnProperty(provider)) {
provider = cdn_providers[provider];
}
return provider.replace(/\${\s*package\s*}/gi, package)
.replace(/\${\s*version\s*}/gi, version)
.replace(/\${\s*filename\s*}/gi, filename);
});
hexo.extend.helper.register('fontcdn', function (fontName) {
let provider = hexo.extend.helper.get('get_config').bind(this)('providers.fontcdn');
if (provider !== null && font_providers.hasOwnProperty(provider)) {
provider = font_providers[provider];
}
return provider.replace(/\${\s*fontname\s*}/gi, fontName);
});
hexo.extend.helper.register('iconcdn', function (provider = null) {
if (provider !== null && icon_providers.hasOwnProperty(provider)) {
provider = icon_providers[provider];
} else {
provider = hexo.extend.helper.get('get_config').bind(this)('providers.iconcdn');
if (provider !== null && icon_providers.hasOwnProperty(provider)) {
provider = icon_providers[provider];
}
}
return provider;
});
}

View File

@ -0,0 +1,48 @@
/**
* Theme configuration helpers.
*
* @description Test if a configuration is set or fetch its value. If `exclude_page` is set, the helpers will
* not look up configurations in the current page's front matter.
* @example
* <%- has_config(config_name, exclude_page) %>
* <%- get_config(config_name, default_value, exclude_page) %>
*/
const specs = require('../specs/config.spec');
const descriptors = require('../common/utils').descriptors;
module.exports = function (hexo) {
function readProperty(object, path) {
const paths = path.split('.');
for (let path of paths) {
if (typeof (object) === 'undefined' || object === null || !object.hasOwnProperty(path)) {
return null;
}
object = object[path];
}
return object;
}
hexo.extend.helper.register('get_config', function (configName, defaultValue = undefined, excludePage = false) {
const value = readProperty(Object.assign({}, this.config, hexo.theme.config,
!excludePage ? this.page : {}), configName);
if (value === null) {
if (typeof(defaultValue) !== 'undefined') {
return defaultValue;
} else {
const property = readProperty(specs, configName);
return property === null ? null : property[descriptors.defaultValue];
}
}
return value;
});
hexo.extend.helper.register('has_config', function (configName, excludePage = false) {
const readProperty = hexo.extend.helper.get('get_config').bind(this);
return readProperty(configName, null, excludePage) != null;
});
hexo.extend.helper.register('get_config_from_obj', function (object, configName, defaultValue = null) {
const value = readProperty(object, configName);
return value === null ? defaultValue : value;
});
}

View File

@ -0,0 +1,31 @@
/**
* Helper functions for controlling layout.
*
* @example
* <%- get_widgets(position) %>
* <%- has_column() %>
* <%- column_count() %>
*/
module.exports = function (hexo) {
hexo.extend.helper.register('get_widgets', function (position) {
const hasWidgets = hexo.extend.helper.get('has_config').bind(this)('widgets');
if (!hasWidgets) {
return [];
}
const widgets = hexo.extend.helper.get('get_config').bind(this)('widgets');
return widgets.filter(widget => widget.hasOwnProperty('position') && widget.position === position);
});
hexo.extend.helper.register('has_column', function (position) {
const getWidgets = hexo.extend.helper.get('get_widgets').bind(this);
return getWidgets(position).length > 0;
});
hexo.extend.helper.register('column_count', function () {
let columns = 1;
const hasColumn = hexo.extend.helper.get('has_column').bind(this);
columns += hasColumn('left') ? 1 : 0;
columns += hasColumn('right') ? 1 : 0;
return columns;
});
}

View File

@ -0,0 +1,124 @@
/**
* Helper functions that override Hexo built-in helpers.
*
* @example
* <%- _list_archives() %>
* <%- _list_categories() %>
* <%- _list_tags() %>
* <%- _toc() %>
*/
const cheerio = require('cheerio');
module.exports = function (hexo) {
hexo.extend.helper.register('_list_archives', function () {
const $ = cheerio.load(this.list_archives(), { decodeEntities: false });
const archives = [];
$('.archive-list-item').each(function () {
archives.push({
url: $(this).find('.archive-list-link').attr('href'),
name: $(this).find('.archive-list-link').text(),
count: $(this).find('.archive-list-count').text()
});
});
return archives;
});
hexo.extend.helper.register('_list_categories', function () {
const $ = cheerio.load(this.list_categories({ depth: 2 }), { decodeEntities: false });
function traverse(root) {
const categories = [];
root.find('> .category-list-item').each(function () {
const category = {
url: $(this).find('> .category-list-link').attr('href'),
name: $(this).find('> .category-list-link').text(),
count: $(this).find('> .category-list-count').text()
};
if ($(this).find('> .category-list-child').length) {
category['children'] = traverse($(this).find('> .category-list-child'));
}
categories.push(category);
});
return categories;
}
return traverse($('.category-list'));
});
hexo.extend.helper.register('_list_tags', function () {
const $ = cheerio.load(this.list_tags(), { decodeEntities: false });
const tags = [];
$('.tag-list-item').each(function () {
tags.push({
url: $(this).find('.tag-list-link').attr('href'),
name: $(this).find('.tag-list-link').text(),
count: $(this).find('.tag-list-count').text()
});
});
return tags;
});
/**
* Export a tree of headings of an article
* {
* "1": {
* "id": "How-to-enable-table-of-content-for-a-post",
* "index": "1"
* },
* "2": {
* "1": {
* "1": {
* "id": "Third-level-title",
* "index": "2.1.1"
* },
* "id": "Second-level-title",
* "index": "2.1"
* },
* "2": {
* "id": "Another-second-level-title",
* "index": "2.2"
* },
* "id": "First-level-title",
* "index": "2"
* }
* }
*/
hexo.extend.helper.register('_toc', (content) => {
const $ = cheerio.load(content, { decodeEntities: false });
const toc = {};
const levels = [0, 0, 0];
// Get top 3 headings that are present in the content
const tags = [1, 2, 3, 4, 5, 6].map(i => 'h' + i).filter(h => $(h).length > 0).slice(0, 3);
if (tags.length === 0) {
return toc;
}
$(tags.join(',')).each(function () {
const level = tags.indexOf(this.name);
const id = $(this).attr('id');
const text = $(this).text();
for (let i = 0; i < levels.length; i++) {
if (i > level) {
levels[i] = 0;
} else if (i < level) {
if (levels[i] === 0) {
// if headings start with a lower level heading, set the former heading index to 1
// e.g. h3, h2, h1, h2, h3 => 1.1.1, 1.2, 2, 2.1, 2.1.1
levels[i] = 1;
}
} else {
levels[i] += 1;
}
}
let node = toc;
for (let i of levels.slice(0, level + 1)) {
if (!node.hasOwnProperty(i)) {
node[i] = {};
}
node = node[i];
}
node.id = id;
node.text = text;
node.index = levels.slice(0, level + 1).join('.');
});
return toc;
});
}

96
includes/helpers/page.js Normal file
View File

@ -0,0 +1,96 @@
/**
* Helper functions for page/post.
*
* @example
* <%- is_categories(page) %>
* <%- is_tags(page) %>
* <%- page_title(page) %>
* <%- meta(post) %>
* <%- has_thumbnail(post) %>
* <%- get_thumbnail(post) %>
*/
module.exports = function (hexo) {
function trim(str) {
return str.trim().replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1');
}
function split(str, sep) {
var result = [];
var matched = null;
while (matched = sep.exec(str)) {
result.push(matched[0]);
}
return result;
}
hexo.extend.helper.register('is_categories', function (page = null) {
return (page === null ? this.page : page).__categories;
});
hexo.extend.helper.register('is_tags', function (page = null) {
return (page === null ? this.page : page).__tags;
});
/**
* Generate html head title based on page type
*/
hexo.extend.helper.register('page_title', function (page = null) {
page = page === null ? this.page : page;
let title = page.title;
if (this.is_archive()) {
title = this._p('common.archive', Infinity);
if (this.is_month()) {
title += ': ' + page.year + '/' + page.month;
} else if (this.is_year()) {
title += ': ' + page.year;
}
} else if (this.is_category()) {
title = this._p('common.category', 1) + ': ' + page.category;
} else if (this.is_tag()) {
title = this._p('common.tag', 1) + ': ' + page.tag;
} else if (this.is_categories()) {
title = this._p('common.category', Infinity);
} else if (this.is_tags()) {
title = this._p('common.tag', Infinity);
}
const siteTitle = hexo.extend.helper.get('get_config').bind(this)('title', '', true);
return [title, siteTitle].filter(str => typeof (str) !== 'undefined' && str.trim() !== '').join(' - ');
});
hexo.extend.helper.register('meta', function (post) {
var metas = post.meta || [];
var output = '';
var metaDOMArray = metas.map(function (meta) {
var entities = split(meta, /(?:[^\\;]+|\\.)+/g);
var entityArray = entities.map(function (entity) {
var keyValue = split(entity, /(?:[^\\=]+|\\.)+/g);
if (keyValue.length < 2) {
return null;
}
var key = trim(keyValue[0]);
var value = trim(keyValue[1]);
return key + '="' + value + '"';
}).filter(function (entity) {
return entity;
});
return '<meta ' + entityArray.join(' ') + ' />';
});
return metaDOMArray.join('\n');
});
hexo.extend.helper.register('has_thumbnail', function (post) {
const getConfig = hexo.extend.helper.get('get_config').bind(this);
const allowThumbnail = getConfig('article.thumbnail', true);
if (!allowThumbnail) {
return false;
}
return post.hasOwnProperty('thumbnail') && post.thumbnail;
});
hexo.extend.helper.register('get_thumbnail', function (post) {
const hasThumbnail = hexo.extend.helper.get('has_thumbnail').bind(this)(post);
return this.url_for(hasThumbnail ? post.thumbnail : 'images/thumbnail.svg');
});
}

53
includes/helpers/site.js Normal file
View File

@ -0,0 +1,53 @@
/**
* Helper functions related the site properties.
*
* @example
* <%- is_same_link(url_a, url_b) %>
* <%- post_count() %>
* <%- category_count() %>
* <%- tag_count() %>
* <%- duration() %>
* <%- word_count(content) %>
*/
const moment = require('moment');
module.exports = function (hexo) {
hexo.extend.helper.register('is_same_link', function (a, b) {
function santize(url) {
let paths = url.replace(/(^\w+:|^)\/\//, '').split('#')[0].split('/').filter(p => p.trim() !== '');
if (paths.length > 0 && paths[paths.length - 1].trim() === 'index.html') {
paths = paths.slice(0, paths.length - 1)
}
return paths.join('/');
}
return santize(this.url_for(a)) == santize(this.url_for(b));
});
hexo.extend.helper.register('post_count', function () {
return this.site.posts.length;
});
hexo.extend.helper.register('category_count', function () {
return this.site.categories.filter(category => category.length).length;
});
hexo.extend.helper.register('tag_count', function () {
return this.site.tags.filter(tag => tag.length).length;
});
/**
* Export moment.duration
*/
hexo.extend.helper.register('duration', function () {
return moment.duration.apply(moment, arguments);
});
/**
* Get the word count of a paragraph.
*/
hexo.extend.helper.register('word_count', function (content) {
content = content.replace(/<\/?[a-z][^>]*>/gi, '');
content = content.trim();
return content ? (content.match(/[\u00ff-\uffff]|[a-zA-Z]+/g) || []).length : 0;
});
}

View File

@ -0,0 +1,21 @@
const { doc, type, defaultValue } = require('../common/utils').descriptors;
module.exports = {
[type]: 'object',
[doc]: 'Article display settings',
highlight: {
[type]: 'string',
[doc]: 'Code highlight theme (https://github.com/highlightjs/highlight.js/tree/master/src/styles)',
[defaultValue]: 'atom-one-light'
},
thumbnail: {
[type]: 'boolean',
[doc]: 'Whether to show article thumbnail images',
[defaultValue]: true
},
readtime: {
[type]: 'boolean',
[doc]: 'Whether to show estimate article reading time',
[defaultValue]: true
}
};

View File

@ -0,0 +1,119 @@
const { doc, type, defaultValue, required, requires } = require('../common/utils').descriptors;
const ChangYanSpec = {
appid: {
[type]: 'string',
[doc]: 'Changyan comment app ID',
[required]: true,
[requires]: comment => comment.type === 'changyan'
},
conf: {
[type]: 'string',
[doc]: 'Changyan comment configuration ID',
[required]: true,
[requires]: comment => comment.type === 'changyan'
}
};
const DisqusSpec = {
shortname: {
[type]: 'string',
[doc]: 'Disqus shortname',
[required]: true,
[requires]: comment => comment.type === 'disqus'
}
};
const GitmentSpec = {
owner: {
[type]: 'string',
[doc]: 'Your GitHub ID',
[required]: true,
[requires]: comment => comment.type === 'gitment'
},
repo: {
[type]: 'string',
[doc]: 'The repo to store comments',
[required]: true,
[requires]: comment => comment.type === 'gitment'
},
client_id: {
[type]: 'string',
[doc]: 'Your client ID',
[required]: true,
[requires]: comment => comment.type === 'gitment'
},
client_secret: {
[type]: 'string',
[doc]: 'Your client secret',
[required]: true,
[requires]: comment => comment.type === 'gitment'
}
};
const IssoSpec = {
url: {
[type]: 'string',
[doc]: 'URL to your Isso comment service',
[required]: true,
[requires]: comment => comment.type === 'isso'
}
};
const LiveReSpec = {
uid: {
[type]: 'string',
[doc]: 'LiveRe comment service UID',
[required]: true,
[requires]: comment => comment.type === 'livere'
}
};
const ValineSpec = {
app_id: {
[type]: 'boolean',
[doc]: 'LeanCloud APP ID',
[required]: true,
[requires]: comment => comment.type === 'valine'
},
app_key: {
[type]: 'boolean',
[doc]: 'LeanCloud APP key',
[required]: true,
[requires]: comment => comment.type === 'valine'
},
notify: {
[type]: 'boolean',
[doc]: 'Enable email notification when someone comments',
[defaultValue]: false,
[requires]: comment => comment.type === 'valine'
},
verify: {
[type]: 'boolean',
[doc]: 'Enable verification code service',
[defaultValue]: false,
[requires]: comment => comment.type === 'valine'
},
placeholder: {
[type]: 'boolean',
[doc]: 'Placeholder text in the comment box',
[defaultValue]: 'Say something...',
[requires]: comment => comment.type === 'valine'
}
};
module.exports = {
[type]: 'object',
[doc]: 'Comment plugin settings (http://ppoffice.github.io/hexo-theme-icarus/categories/Configuration/Comment-Plugins)',
type: {
[type]: 'string',
[doc]: 'Name of the comment plugin',
[defaultValue]: null
},
...ChangYanSpec,
...DisqusSpec,
...GitmentSpec,
...IssoSpec,
...LiveReSpec,
...ValineSpec
}

View File

@ -0,0 +1,24 @@
const { version } = require('../../package.json');
const { type, required, defaultValue, doc } = require('../common/utils').descriptors;
module.exports = {
[type]: 'object',
[doc]: 'Root of the configuration file',
[required]: true,
version: {
[type]: 'string',
[doc]: 'Version of the Icarus theme that is currently used',
[required]: true,
[defaultValue]: version
},
...require('./meta.spec'),
navbar: require('./navbar.spec'),
footer: require('./footer.spec'),
article: require('./article.spec'),
search: require('./search.spec'),
comment: require('./comment.spec'),
share: require('./share.spec'),
widgets: require('./widgets.spec'),
plugins: require('./plugins.spec'),
providers: require('./providers.spec')
};

View File

@ -0,0 +1,24 @@
const { doc, type, defaultValue } = require('../common/utils').descriptors;
module.exports = {
[type]: 'object',
[doc]: 'Footer section link settings',
links: {
...require('./icon_link.spec'),
[doc]: 'Links to be shown on the right of the footer section',
[defaultValue]: {
'Creative Commons': {
icon: 'fab fa-creative-commons',
url: 'https://creativecommons.org/'
},
'Attribution 4.0 International': {
icon: 'fab fa-creative-commons-by',
url: 'https://creativecommons.org/licenses/by/4.0/'
},
'Download on GitHub': {
icon: 'fab fa-github',
url: 'http://github.com/ppoffice/hexo-theme-icarus'
}
}
}
};

View File

@ -0,0 +1,20 @@
const { doc, type, required } = require('../common/utils').descriptors;
module.exports = {
[type]: 'object',
[doc]: 'Link icon settings',
'*': {
[type]: ['string', 'object'],
[doc]: 'Path or URL to the menu item, and/or link icon class names',
icon: {
[required]: true,
[type]: 'string',
[doc]: 'Link icon class names'
},
url: {
[required]: true,
[type]: 'string',
[doc]: 'Path or URL to the menu item'
}
}
};

View File

@ -0,0 +1,52 @@
const { doc, type, defaultValue } = require('../common/utils').descriptors;
module.exports = {
favicon: {
[type]: 'string',
[doc]: 'Path or URL to the website\'s icon',
[defaultValue]: '/images/favicon.svg',
},
rss: {
[type]: 'string',
[doc]: 'Path or URL to RSS atom.xml',
[defaultValue]: null
},
logo: {
[type]: ['string', 'object'],
[defaultValue]: '/images/logo.svg',
[doc]: 'Path or URL to the website\'s logo to be shown on the left of the navigation bar or footer',
text: {
[type]: 'string',
[doc]: 'Text to be shown in place of the logo image'
}
},
open_graph: {
[type]: 'object',
[doc]: 'Open Graph metadata (https://hexo.io/docs/helpers.html#open-graph)',
fb_app_id: {
[type]: 'string',
[doc]: 'Facebook App ID',
[defaultValue]: null
},
fb_admins: {
[type]: 'string',
[doc]: 'Facebook Admin ID',
[defaultValue]: null
},
twitter_id: {
[type]: 'string',
[doc]: 'Twitter ID',
[defaultValue]: null
},
twitter_site: {
[type]: 'string',
[doc]: 'Twitter site',
[defaultValue]: null
},
google_plus: {
[type]: 'string',
[doc]: 'Google+ profile link',
[defaultValue]: null
}
}
};

View File

@ -0,0 +1,31 @@
const { doc, type, defaultValue } = require('../common/utils').descriptors;
module.exports = {
[type]: 'object',
[doc]: 'Navigation bar link settings',
menu: {
[type]: 'object',
[doc]: 'Navigation bar menu links',
[defaultValue]: {
Home: '/',
Archives: '/archives',
Categories: '/categories',
Tags: '/tags',
About: '/about'
},
'*': {
[type]: 'string',
[doc]: 'Path or URL to the menu item'
}
},
links: {
...require('./icon_link.spec'),
[doc]: 'Navigation bar links to be shown on the right',
[defaultValue]: {
'Download on GitHub': {
icon: 'fab fa-github',
url: 'http://github.com/ppoffice/hexo-theme-icarus'
}
}
}
};

View File

@ -0,0 +1,49 @@
const { doc, type, defaultValue, required, requires } = require('../common/utils').descriptors;
module.exports = {
[type]: 'object',
[doc]: 'Other plugin settings',
gallery: {
[type]: 'boolean',
[doc]: 'Enable the lightGallery and Justified Gallery plugins (http://ppoffice.github.io/hexo-theme-icarus/2016/07/08/plugin/Gallery/)',
[defaultValue]: true
},
'outdated-browser': {
[type]: 'boolean',
[doc]: 'Enable the Outdated Browser plugin (http://outdatedbrowser.com/)',
[defaultValue]: true
},
animejs: {
[type]: 'boolean',
[doc]: 'Enable page animations (http://animejs.com/)',
[defaultValue]: true
},
mathjax: {
[type]: 'boolean',
[doc]: 'Enable the MathJax plugin (http://ppoffice.github.io/hexo-theme-icarus/2018/01/01/plugin/MathJax/)',
[defaultValue]: true
},
'back-to-top': {
[type]: 'boolean',
[doc]: 'Show the back to top button on mobile devices',
[defaultValue]: true
},
'google-analytics': {
[type]: ['boolean', 'object'],
[doc]: 'Google Analytics plugin settings (http://ppoffice.github.io/hexo-theme-icarus/2018/01/01/plugin/Analytics/#Google-Analytics)',
tracking_id: {
[type]: 'string',
[doc]: 'Google Analytics tracking id',
[defaultValue]: null
}
},
'baidu-analytics': {
[type]: ['boolean', 'object'],
[doc]: 'Baidu Analytics plugin settings (http://ppoffice.github.io/hexo-theme-icarus/2018/01/01/plugin/Analytics/#Baidu-Analytics)',
tracking_id: {
[type]: 'string',
[doc]: 'Baidu Analytics tracking id',
[defaultValue]: null
}
}
};

View File

@ -0,0 +1,21 @@
const { doc, type, defaultValue } = require('../common/utils').descriptors;
module.exports = {
[type]: 'object',
[doc]: 'CDN provider settings',
cdn: {
[type]: 'string',
[doc]: 'Name or URL of the JavaScript and/or stylesheet CDN provider',
[defaultValue]: 'cdnjs'
},
fontcdn: {
[type]: 'string',
[doc]: 'Name or URL of the webfont CDN provider',
[defaultValue]: 'google'
},
iconcdn: {
[type]: 'string',
[doc]: 'Name or URL of the webfont Icon CDN provider',
[defaultValue]: 'fontawesome'
}
};

View File

@ -0,0 +1,17 @@
const { doc, type, defaultValue, required, requires } = require('../common/utils').descriptors;
module.exports = {
[type]: 'object',
[doc]: 'Search plugin settings (http://ppoffice.github.io/hexo-theme-icarus/categories/Configuration/Search-Plugins)',
type: {
[type]: 'string',
[doc]: 'Name of the search plugin',
[defaultValue]: 'insight'
},
cx: {
[type]: 'string',
[doc]: 'Google CSE cx value',
[required]: true,
[requires]: search => search.type === 'google-cse'
}
};

View File

@ -0,0 +1,17 @@
const { doc, type, defaultValue, required, requires } = require('../common/utils').descriptors;
module.exports = {
[type]: 'object',
[doc]: 'Share plugin settings (http://ppoffice.github.io/hexo-theme-icarus/categories/Configuration/Share-Plugins)',
type: {
[type]: 'string',
[doc]: 'Share plugin name',
[defaultValue]: null
},
install_url: {
[type]: 'string',
[doc]: 'URL to the share plugin script provided by share plugin service provider',
[required]: true,
[requires]: share => share.type === 'sharethis' || share.type === 'addthis'
}
}

View File

@ -0,0 +1,145 @@
const { doc, type, defaultValue, required, requires, format } = require('../common/utils').descriptors;
const DEFAULT_WIDGETS = [
{
type: 'profile',
position: 'left',
author: 'Your name',
author_title: 'Your title',
location: 'Your location',
avatar: null,
gravatar: null,
follow_link: 'http://github.com/ppoffice',
social_links: {
Github: {
icon: 'fab fa-github',
url: 'http://github.com/ppoffice'
},
Facebook: {
icon: 'fab fa-facebook',
url: 'http://facebook.com'
},
Twitter: {
icon: 'fab fa-twitter',
url: 'http://twitter.com'
},
Dribbble: {
icon: 'fab fa-dribbble',
url: 'http://dribbble.com'
},
RSS: {
icon: 'fas fa-rss',
url: '/'
}
}
},
{
type: 'toc',
position: 'left'
},
{
type: 'links',
position: 'left',
links: {
Hexo: 'https://hexo.io',
PPOffice: 'https://github.com/ppoffice'
}
},
{
type: 'category',
position: 'left'
},
{
type: 'tagcloud',
position: 'left'
},
{
type: 'recent_posts',
position: 'right'
},
{
type: 'archive',
position: 'right'
},
{
type: 'tag',
position: 'right'
}
];
const ProfileSpec = {
author: {
[type]: 'string',
[doc]: 'Author name to be shown in the profile widget',
[defaultValue]: 'Your name'
},
author_title: {
[type]: 'string',
[doc]: 'Title of the author to be shown in the profile widget',
[defaultValue]: 'Your title'
},
location: {
[type]: 'string',
[doc]: 'Author\'s current location to be shown in the profile widget',
[defaultValue]: 'Your location'
},
avatar: {
[type]: 'string',
[doc]: 'Path or URL to the avatar to be shown in the profile widget',
[defaultValue]: '/images/avatar.png'
},
gravatar: {
[type]: 'string',
[doc]: 'Email address for the Gravatar to be shown in the profile widget',
},
follow_link: {
[type]: 'string',
[doc]: 'Path or URL for the follow button',
},
social_links: {
...require('./icon_link.spec'),
[doc]: 'Links to be shown on the bottom of the profile widget',
}
};
for (let key in ProfileSpec) {
ProfileSpec[key][requires] = widget => widget.type === 'profile';
}
const LinksSpec = {
links: {
[type]: 'object',
[doc]: 'Links to be shown in the links widget',
[requires]: parent => parent.type === 'links',
'*': {
[type]: 'string',
[doc]: 'Path or URL to the link',
[required]: true
}
}
};
module.exports = {
[type]: 'array',
[doc]: 'Sidebar widget settings (http://ppoffice.github.io/hexo-theme-icarus/categories/Widgets/)',
[defaultValue]: DEFAULT_WIDGETS,
'*': {
[type]: 'object',
[doc]: 'Single widget settings',
type: {
[type]: 'string',
[doc]: 'Widget name',
[required]: true,
[defaultValue]: 'profile'
},
position: {
[type]: 'string',
[doc]: 'Where should the widget be placed, left or right',
[format]: /^(left|right)$/,
[required]: true,
[defaultValue]: 'left'
},
...ProfileSpec,
...LinksSpec
}
}

View File

@ -0,0 +1,46 @@
const fs = require('fs');
const util = require('util');
const path = require('path');
const logger = require('hexo-log')();
const yaml = require('js-yaml');
const { errors } = require('../common/utils');
const rootSpec = require('../specs/config.spec');
const ConfigValidator = require('../common/ConfigValidator');
const ConfigGenerator = require('../common/ConfigGenerator');
const CONFIG_PATH = path.join(__dirname, '../..', '_config.yml');
logger.info('Validating the configuration file');
if (!fs.existsSync(CONFIG_PATH)) {
const relativePath = path.relative(process.cwd(), CONFIG_PATH);
logger.warn(`${relativePath} is not found. We are creating one for you...`);
fs.writeFileSync(CONFIG_PATH, new ConfigGenerator(rootSpec).generate());
logger.info(`${relativePath} is created. Please restart Hexo to apply changes.`);
process.exit(0);
}
const validator = new ConfigValidator(rootSpec);
const config = yaml.safeLoad(fs.readFileSync(CONFIG_PATH));
try {
validator.validate(config);
} catch (e) {
if (e instanceof errors.ConfigError) {
logger.error(e.message);
if (e.hasOwnProperty('spec')) {
logger.error('The specification of this configuration is:');
logger.error(util.inspect(e.spec));
}
if (e.hasOwnProperty('config')) {
logger.error('Configuration value is:');
logger.error(util.inspect(e.config));
}
} else if (e instanceof errors.VersionError) {
logger.error(e.message);
logger.warn(`To let us create a fresh configuration file for you, please rename or delete the following file:`);
logger.warn(CONFIG_PATH);
} else {
throw e;
}
}

View File

@ -0,0 +1,32 @@
const logger = require('hexo-log')();
function checkDependency(name) {
try {
require.resolve(name);
return true;
} catch(e) {
logger.error(`Package ${name} is not installed.`)
}
return false;
}
logger.info('Checking dependencies');
const missingDeps = [
'js-yaml',
'moment',
'cheerio',
'hexo-util',
'hexo-log',
'hexo-pagination',
'hexo-generator-archive',
'hexo-generator-category',
'hexo-generator-index',
'hexo-generator-tag',
'hexo-renderer-ejs',
'hexo-renderer-marked',
'hexo-renderer-stylus',
].map(checkDependency).some(installed => !installed);
if (missingDeps) {
logger.error('Please install the missing dependencies from the root directory of your Hexo site.');
process.exit(-1);
}

10
includes/tasks/welcome.js Normal file
View File

@ -0,0 +1,10 @@
const logger = require('hexo-log')();
logger.info(`=======================================
=============================================`);

View File

@ -1,33 +1,35 @@
index:
home: 'home'
search: 'Search'
archive: 'archive'
category: 'category'
uncategorized: 'uncategorized'
tag: 'tag'
nav:
common:
archive:
one: 'Archive'
other: 'Archives'
category:
one: 'Category'
other: 'Categories'
tag:
one: 'Tag'
other: 'Tags'
post:
one: 'Post'
other: 'Posts'
prev: 'Previous'
next: 'Next'
prev: 'Prev'
older: 'Older'
newer: 'Newer'
widget:
recents: 'recent'
archives: 'archives'
categories: 'categories'
links: 'links'
tags: 'tags'
tag_cloud: 'tag cloud'
follow: 'Follow'
recents: 'Recent'
links: 'Links'
tag_cloud: 'Tag Cloud'
catalogue: 'Catalogue'
article:
more: 'Read More'
comments: 'Comments'
share: 'Share'
catalogue: 'Catalogue'
profile:
follow: 'FOLLOW'
post: 'post'
tag: 'tag'
posts: 'posts'
tags: 'tags'
read: 'read'
about: 'About'
words: 'words'
plugin:
backtotop: 'Back to Top'
search:
search: 'Search'
hint: 'Type something...'
insight:
hint: 'Type something...'
posts: 'Posts'
@ -35,4 +37,3 @@ insight:
categories: 'Categories'
tags: 'Tags'
untitled: '(Untitled)'

View File

@ -1,33 +1,34 @@
#By SrWoOoW
index:
home: 'Inicio'
search: 'Buscar'
archive: 'Archivo'
category: 'Categoria'
uncategorized: 'Sin categoría'
tag: 'Etiqueta'
nav:
next: 'Siguiente '
common:
archive:
one: 'Archivo'
other: 'Archivos'
category:
one: 'Categoria'
other: 'Categorias'
tag:
one: 'Etiqueta'
other: 'Etiquetas'
post:
one: 'Entrada'
other: 'Entradas'
prev: 'Anterior'
older: 'Más viejo'
newer: 'Más nuevo'
next: 'Siguiente'
widget:
recents: 'Recientes'
archives: 'Archivos'
categories: 'Categorias'
links: 'Links'
tags: 'Etiquetas'
tag_cloud: 'Nube de etiquetas'
article:
comments: 'Comentarios'
share: 'Compartir'
catalogue: 'Catálogo'
profile:
follow: 'SEGUIR'
post: 'Entrada'
tag: 'Etiqueta'
posts: 'Entradas'
tags: 'Etiquetas'
recents: 'Recientes'
links: 'Links'
tag_cloud: 'Nube de etiquetas'
catalogue: 'Catálogo'
article:
more: 'Read More'
comments: 'Comentarios'
read: 'read'
about: 'About'
words: 'words'
search:
search: 'Search'
hint: 'Type something...'
insight:
hint: 'Type something...'
posts: 'Entradas'

View File

@ -1,32 +1,33 @@
index:
home: 'Racine'
search: 'Rechercher'
archive: 'Archive'
category: 'Catégorie'
uncategorized: 'Sans catégorie'
tag: 'Tag'
nav:
next: 'Suiv'
common:
archive:
one: 'Archive'
other: 'Archives'
category:
one: 'Catégorie'
other: 'Catégories'
tag:
one: 'Tag'
other: 'Tags'
post:
one: 'Article'
other: 'Articles'
prev: 'Préc'
older: 'Plus ancien'
newer: 'Plus récent'
next: 'Suiv'
widget:
recents: 'Récents'
archives: 'Archives'
categories: 'Catégories'
links: 'Liens'
tags: 'Tags'
tag_cloud: 'Nuage de tags'
article:
comments: 'Commentaires'
share: 'Partager'
catalogue: 'Catalogue'
profile:
follow: 'SUIVRE'
post: 'Article'
tag: 'Tag'
posts: 'Articles'
tags: 'Tags'
recents: 'Récents'
links: 'Liens'
tag_cloud: 'Nuage de tags'
catalogue: 'Catalogue'
article:
more: 'Read More'
comments: 'Commentaires'
read: 'read'
about: 'About'
words: 'words'
search:
search: 'Search'
hint: 'Type something...'
insight:
hint: 'Type something...'
posts: 'Articles'

View File

@ -1,31 +1,33 @@
index:
home: 'Beranda'
search: 'Cari'
archive: 'Arsip'
category: 'Kategori'
uncategorized: 'Tanpa Kategori'
tag: 'tag'
nav:
next: 'Berikutnya'
common:
archive:
one: 'Arsip'
other: 'Arsip'
category:
one: 'Kategori'
other: 'Kategori'
tag:
one: 'tag'
other: 'tag'
post:
one: 'pos'
other: 'pos'
prev: 'Sebelumnya'
older: 'Lebih lama'
newer: 'Lebih baru'
next: 'Berikutnya'
widget:
recents: 'Terbaru'
archives: 'Arsip'
categories: 'Kategori'
links: 'tautan'
tags: 'tag'
tag_cloud: 'awan tag'
article:
comments: 'Komentar'
share: 'Bagikan'
profile:
follow: 'IKUTI'
post: 'pos'
tag: 'tag'
posts: 'pos'
tags: 'tag'
recents: 'Terbaru'
links: 'tautan'
tag_cloud: 'awan tag'
catalogue: 'Catalogue'
article:
more: 'Read More'
comments: 'Komentar'
read: 'read'
about: 'About'
words: 'words'
search:
search: 'Search'
hint: 'Tulis Sesuatu..'
insight:
hint: 'Tulis Sesuatu..'
posts: 'Pos'

View File

@ -1,32 +1,33 @@
index:
home: 'ホーム'
search: '検索'
archive: 'アーカイブ'
category: 'カテゴリ'
uncategorized: '未分類'
tag: 'タグ'
nav:
next: '次'
common:
archive:
one: 'アーカイブ'
other: 'アーカイブ'
category:
one: 'カテゴリ'
other: 'カテゴリ'
tag:
one: 'タグ'
other: 'タグ'
post:
one: '投稿'
other: '投稿'
prev: '前'
older: '古い記事'
newer: '新しい記事'
next: '次'
widget:
recents: '最近の記事'
archives: 'アーカイブ'
categories: 'カテゴリ'
links: 'リンク'
tags: 'タグ'
tag_cloud: 'タグクラウド'
article:
comments: 'コメント'
share: '共有'
catalogue: 'カタログ'
profile:
follow: 'フォローする'
post: '投稿'
tag: 'タグ'
posts: '投稿'
tags: 'タグ'
recents: '最近の記事'
links: 'リンク'
tag_cloud: 'タグクラウド'
catalogue: 'カタログ'
article:
more: 'Read More'
comments: 'コメント'
read: 'read'
about: 'About'
words: 'words'
search:
search: 'Search'
hint: 'Type something...'
insight:
hint: 'Type something...'
posts: '投稿'

View File

@ -1,33 +1,33 @@
index:
home: '홈'
search: '검색'
archive: '아카이브'
category: '카테고리'
uncategorized: '미지정'
tag: '태그'
nav:
next: '다음'
common:
archive:
one: '아카이브'
other: '아카이브'
category:
one: '카테고리'
other: '카테고리'
tag:
one: '태그'
other: '태그'
post:
one: '포스트'
other: '포스트'
prev: '이전'
older: '이전 글'
newer: '다음 글'
next: '다음'
widget:
follow: '팔로우'
recents: '최근 글'
archives: '아카이브'
categories: '카테고리'
links: '링크'
tags: '태그'
tag_cloud: '태그 클라우드'
catalogue: '카탈로그'
article:
more: '자세히 보기'
comments: '댓글'
share: '공유하기'
catalogue: '카탈로그'
profile:
follow: '팔로우'
post: '포스트'
tag: '태그'
posts: '포스트'
tags: '태그'
read: 'read'
about: 'About'
words: 'words'
search:
search: 'Search'
hint: 'Type something...'
insight:
hint: 'Type something...'
posts: '포스트'

View File

@ -1,33 +1,33 @@
index:
home: 'home'
search: 'Pesquisar'
archive: 'arquivo'
category: 'categoria'
uncategorized: 'Sem categoria'
tag: 'tag'
nav:
next: 'Próximo'
common:
archive:
one: 'Arquivo'
other: 'Arquivos'
category:
one: 'Categoria'
other: 'Categorias'
tag:
one: 'Tag'
other: 'Tags'
post:
one: 'Artigo'
other: 'Artigos'
prev: 'Anterior'
older: 'Antigos'
newer: 'Novos'
next: 'Próximo'
widget:
follow: 'SEGUIR'
recents: 'Recentes'
archives: 'Arquivos'
categories: 'Categorias'
links: 'Links'
tags: 'Tags'
tag_cloud: 'Nuvem de tags'
catalogue: 'Catálogo'
article:
more: 'Ler Mais'
comments: 'Comentarios'
share: 'Compartilhar'
catalogue: 'Catálogo'
profile:
follow: 'SEGUIR'
post: 'Artigo'
tag: 'Tag'
posts: 'Artigos'
tags: 'Tags'
read: 'read'
about: 'About'
words: 'words'
search:
search: 'Search'
hint: 'Digite alguma coisa...'
insight:
hint: 'Digite alguma coisa...'
posts: 'Artigos'
@ -35,4 +35,3 @@ insight:
categories: 'Categorias'
tags: 'Tags'
untitled: '(Untitled)'

View File

@ -1,33 +1,33 @@
index:
home: 'Главная'
search: 'Поиск'
archive: 'архив'
category: 'категории'
uncategorized: 'без категории'
tag: 'тег'
nav:
next: 'Далее'
common:
archive:
one: 'архив'
other: 'архивы'
category:
one: 'категории'
other: 'категории'
tag:
one: 'тег'
other: 'теги'
post:
one: 'пост'
other: 'посты'
prev: 'Назад'
older: 'Старые'
newer: 'Новые'
next: 'Далее'
widget:
follow: 'Подписаться'
recents: 'недавние'
archives: 'архивы'
categories: 'категории'
links: 'ссылки'
tags: 'теги'
tag_cloud: 'облако тегов'
catalogue: 'Каталог'
article:
more: 'Читать дальше'
comments: 'Комментарии'
share: 'Поделиться'
catalogue: 'Каталог'
profile:
follow: 'Подписаться'
post: 'пост'
tag: 'тег'
posts: 'посты'
tags: 'теги'
read: 'read'
about: 'About'
words: 'words'
search:
search: 'Search'
hint: 'Введите что-нибудь...'
insight:
hint: 'Введите что-нибудь...'
posts: 'посты'

View File

@ -1,33 +1,33 @@
index:
home: 'Anasayfa'
search: 'Ara'
archive: 'Arşiv'
category: 'Kategori'
uncategorized: 'Kategorisiz'
tag: 'Etiket'
nav:
next: 'Sonraki'
common:
archive:
one: 'Arşiv'
other: 'Arşivler'
category:
one: 'Kategori'
other: 'Kategoriler'
tag:
one: 'Etiket'
other: 'Etiketler'
post:
one: 'Gönderi'
other: 'Gönderiler'
prev: 'Önceki'
older: 'Eski'
newer: 'Yeni'
next: 'Sonraki'
widget:
follow: 'TAKİP ET'
recents: 'Son'
archives: 'Arşivler'
categories: 'Kategoriler'
links: 'Linkler'
tags: 'Etiketler'
tag_cloud: 'Etiket bulutu'
catalogue: 'Katalog'
article:
more: 'Daha fazla oku'
comments: 'Yorumlar'
share: 'Paylaş'
catalogue: 'Katalog'
profile:
follow: 'TAKİP ET'
post: 'Gönderi'
tag: 'Etiket'
posts: 'Gönderi'
tags: 'Etiket'
read: 'read'
about: 'About'
words: 'words'
search:
search: 'Search'
hint: 'Bir şeyler yaz...'
insight:
hint: 'Bir şeyler yaz...'
posts: 'Gönderiler'

View File

@ -1,37 +1,39 @@
index:
home: '主页'
search: '搜索'
archive: '归档'
category: '分类'
uncategorized: '未分类'
tag: '标签'
nav:
next: '下一页'
common:
archive:
one: '文档'
other: '文档'
category:
one: '分类'
other: '分类'
tag:
one: '标签'
other: '标签'
post:
one: '文章'
other: '文章'
prev: '上一页'
older: '下一篇'
newer: '上一篇'
next: '下一页'
widget:
recents: '最新文章'
archives: '归档'
categories: '分类'
links: '链接'
tags: '标签'
tag_cloud: '标签云'
article:
more: '查看更多'
comments: '评论'
share: '分享到'
catalogue: '文章目录'
profile:
follow: '关注我'
post: '文章'
tag: '标签'
posts: '文章'
tags: '标签'
recents: '最新文章'
links: '链接'
tag_cloud: '标签云'
catalogue: '目录'
article:
more: '阅读更多'
comments: '评论'
read: '读完'
about: '大约'
words: '个字'
plugin:
backtotop: '回到顶端'
search:
search: '搜索'
hint: '想要查找什么...'
insight:
hint: '想要查找什么...'
posts: '文章'
pages: '页面'
categories: '分类'
tags: '标签'
untitled: '(未命名)'
untitled: '(无标题)'

View File

@ -1,33 +1,33 @@
index:
home: '主頁'
search: '搜尋'
archive: '歸檔'
category: '分類'
uncategorized: '未分類'
tag: '標籤'
nav:
next: '下一頁'
common:
archive:
one: '歸檔'
other: '歸檔'
category:
one: '分類'
other: '分類'
tag:
one: '標籤'
other: '標籤'
post:
one: '文章'
other: '文章'
prev: '上一頁'
older: '下一篇'
newer: '上一篇'
next: '下一頁'
widget:
follow: '關注我'
recents: '最新文章'
archives: '歸檔'
categories: '分類'
links: '連結'
tags: '標籤'
tag_cloud: '標籤雲'
catalogue: '文章目錄'
article:
more: '繼續閱讀'
comments: '評論'
share: '分享到'
catalogue: '文章目錄'
profile:
follow: '關注我'
post: '文章'
tag: '標籤'
posts: '文章'
tags: '標籤'
read: 'read'
about: 'About'
words: 'words'
search:
search: '搜索'
hint: 'Type something...'
insight:
hint: 'Type something...'
posts: '文章'

View File

@ -1,32 +1,56 @@
<div class="timeline timeline-wrap">
<% var last;
page.posts.each(function(post, i) {
var year = post.date.year();
if (last != year) {
last = year; %>
<div class="timeline-row timeline-row-major">
<span class="node"><i class="fas fa-calendar-alt"></i></span>
<h1 class="title"><%= year %></h1>
</div>
<% } %>
<div class="timeline-row">
<span class="node"></span>
<div class="content">
<%- partial('common/post/title', { post: post, index: true, class_name: 'timeline-article-title' }) %>
<div class="article-meta">
<%- partial('common/post/date', { post: post, class_name: 'article-date', date_format: null }) %>
<%- partial('common/post/category', { post: post }) %>
<%- partial('common/post/tag', { post: post }) %>
<% function buildArchive(posts, year, month = null) {
const time = moment([page.year, page.month ? page.month - 1 : null].filter(i => i !== null)); %>
<div class="card widget">
<div class="card-content">
<h3 class="tag is-link">
<%= month === null ? year : time.locale(get_config('language', 'en')).format('MMMM YYYY') %>
</h3>
<div class="timeline">
<% posts.each(post => { %>
<article class="media">
<% if (has_thumbnail(post)) { %>
<a href="<%- url_for((post.link?post.link:post.path)) %>" class="media-left">
<p class="image is-64x64">
<img class="thumbnail" src="<%= get_thumbnail(post) %>" alt="<%= post.title %>">
</p>
</a>
<% } %>
<div class="media-content">
<div class="content">
<time class="has-text-grey is-size-7 is-block is-uppercase" datetime="<%= date_xml(post.date) %>"><%= date(post.date) %></time>
<a href="<%- url_for((post.link?post.link:post.path)) %>" class="has-link-black-ter is-size-6"><%= post.title %></a>
<div class="level article-meta is-mobile">
<div class="level-left">
<% if (post.categories && post.categories.length) { %>
<div class="level-item is-size-7 is-uppercase">
<%- list_categories(post.categories, {
class: 'has-link-grey ',
show_count: false,
style: 'none',
separator: '&nbsp;/&nbsp;'
}) %>
</div>
<% } %>
</div>
</div>
</div>
</div>
</div>
</article>
<% }) %>
</div>
<% }); %>
</div>
</div>
<% }
if (!page.year) {
let years = {};
page.posts.each(p => years[p.date.year()] = null);
for (let year of Object.keys(years).sort((a, b) => b - a)) {
let posts = page.posts.filter(p => p.date.year() == year); %>
<%- buildArchive(posts, year, null) %>
<% }
} else { %>
<%- buildArchive(page.posts, page.year, page.month) %>
<% } %>
<% if (page.total > 1) { %>
<nav id="page-nav">
<%- paginator({
prev_text: '&laquo; ' + __('nav.prev'),
next_text: __('nav.next') + ' &raquo;'
}) %>
</nav>
<%- partial('common/paginator') %>
<% } %>

View File

@ -1,10 +1,30 @@
<section class="layout-wrap">
<div class="layout-title">
<span><%= page.title %></span>
<% function build_list(categories) {
return categories.map(category => {
let result = `<li>
<a class="level is-marginless" href="${category.url}">
<span class="level-start">
<span class="level-item">${category.name}</span>
</span>
<span class="level-end">
<span class="level-item tag">${category.count}</span>
</span>
</a>`;
if (category.hasOwnProperty('children')) {
result += '<ul>' + build_list(category.children) + '</ul>';
}
return result + '</li>';
}).join('');
}
%>
<div class="card widget">
<div class="card-content">
<div class="menu">
<h3 class="menu-label">
<%= _p('common.category', Infinity) %>
</h3>
<ul class="menu-list">
<%- build_list(_list_categories()) %>
</ul>
</div>
</div>
<div class="layout-wrap-inner list-categories">
<% if(site.categories.length) { %>
<%- list_categories(site.categories) %>
<% } %>
</div>
</section>
</div>

View File

@ -1 +1,14 @@
<%- partial('common/timeline', { type: 'category' }) %>
<div class="card">
<div class="card-content">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li><a href="<%- url_for('/categories') %>"><%= _p('common.category', Infinity) %></a></li>
<% page.parents.forEach(category => { %>
<li><a href="<%- url_for(category.path) %>"><%= category.name %></a></li>
<% }) %>
<li class="is-active"><a href="#" aria-current="page"><%= page.category %></a></li>
</ul>
</nav>
</div>
</div>
<%- partial('index', { page }) %>

View File

@ -1,12 +1,14 @@
<% if (typeof(script) !== 'undefined' && script) { %>
<script id="cy_cmt_num" src="https://changyan.sohu.com/upload/plugins/plugins.list.count.js?clientId=<%= theme.comment.changyan.appid %>"></script>
<script charset="utf-8" type="text/javascript" src="https://changyan.sohu.com/upload/changyan.js" ></script>
<script type="text/javascript">
window.changyan.api.config({
appid: '<%= theme.comment.changyan.appid %>',
conf: '<%= theme.comment.changyan.conf %>'
});
</script>
<% if (!has_config('comment.appid') || !has_config('comment.conf')) { %>
<div class="notification is-danger">
You forgot to set the <code>appid</code> or <code>conf</code> for Changyan. Please set it in <code>_config.yml</code>.
</div>
<% } else { %>
<div id="SOHUCS" sid="<%= post.path %>"></div>
<div id="SOHUCS" sid="<%= post.path %>"></div>
<script charset="utf-8" type="text/javascript" src="https://changyan.sohu.com/upload/changyan.js" ></script>
<script type="text/javascript">
window.changyan.api.config({
appid: '<%= get_config('comment.appid') %>',
conf: '<%= get_config('comment.conf') %>'
});
</script>
<% } %>

View File

@ -1,17 +0,0 @@
<% if (post.comments) { %>
<% if (theme.comment.disqus) { %>
<a href="<%- post.permalink %>#comments" class="article-comment-link disqus-comment-count" data-disqus-url="<%= post.permalink %>"><%= __('article.comments') %></a>
<% } else if (theme.comment.duoshuo) { %>
<a href="<%- post.permalink %>#comments" class="article-comment-link ds-thread-count" data-thread-key="<%= post.permalink %>"><%= __('article.comments') %></a>
<% } else if (theme.comment.youyan) { %>
<a href="<%- post.permalink %>#comments" class="article-comment-link"><%= __('article.comments') %></a>
<% } else if (theme.comment.isso) { %>
<a href="<%= post.permalink %>#comments" class="article-comment-link"><%= __('article.comments') %></a>
<% } else if (theme.comment.facebook) { %>
<a href="<%= post.permalink %>#comments" class="article-comment-link"><span class="fb-comments-count" data-href="<%= post.permalink %>">0</span>&nbsp;<%= __('article.comments') %></a>
<% } else if (theme.comment.changyan && theme.comment.changyan.appid && theme.comment.changyan.conf) { %>
<a href="<%= post.permalink %>#comments" id="sourceId::<%= post.path %>" class="article-comment-link cy_cmt_count"><%= __('article.comments') %></a>
<% } else if (theme.comment.livere) { %>
<a href="<%- post.permalink %>#comments" class="article-comment-link"><%= __('article.comments') %></a>
<% } %>
<% } %>

View File

@ -1,20 +1,22 @@
<% if (typeof(script) !== 'undefined' && script) { %>
<script>
<% if (has_config('comment.shortname')) { %>
<script>
var disqus_config = function () {
<% if (page.permalink) { %>
this.page.url = '<%= page.permalink %>';
<% } %>
this.page.identifier = '<%= page.disqusId || page.slug %>';
this.page.url = '<%= page.permalink %>';
this.page.identifier = '<%= page.disqusId || page.path %>';
};
(function() {
(function() {
var d = document, s = d.createElement('script');
s.src = '//' + '<%= theme.comment.disqus %>' + '.disqus.com/<% if (page.comments) { %>embed.js<% } else { %>count.js<% } %>';
s.src = '//' + '<%= get_config('comment.shortname') %>' + '.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<% } else { %>
<div id="disqus_thread">
<noscript>Please enable JavaScript to view the <a href="//disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<% } %>
<div id="disqus_thread">
<% if (!has_config('comment.shortname')) { %>
<div class="notification is-danger">
You forgot to set the <code>shortname</code> for Disqus. Please set it in <code>_config.yml</code>.
</div>
<% } %>
<% } %>
<noscript>Please enable JavaScript to view the <a href="//disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>

View File

@ -1,52 +0,0 @@
<% if (typeof(script) !== 'undefined' && script) { %>
<script type="text/javascript">
var duoshuoQuery = {short_name:'<%= theme.comment.duoshuo %>'};
(function() {
var ds = document.createElement('script');
ds.type = 'text/javascript';ds.async = true;
ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
ds.charset = 'UTF-8';
(document.getElementsByTagName('head')[0]
|| document.getElementsByTagName('body')[0]).appendChild(ds);
})();
</script>
<% } else { %>
<div class="ds-thread" data-thread-key="<%= post.path %>" data-title="<%= post.title %>" data-url="<%= page.permalink %>"></div>
<style>
#ds-thread #ds-reset .ds-textarea-wrapper {
background: none;
}
#ds-reset .ds-avatar img {
box-shadow: none;
}
#ds-reset .ds-gradient-bg {
background: #f7f7f7;
}
#ds-thread #ds-reset li.ds-tab a {
border-radius: 3px;
}
#ds-thread #ds-reset .ds-post-button {
color: white;
border: none;
box-shadow: none;
background: #d32;
text-shadow: none;
font-weight: normal;
font-family: 'Microsoft Yahei';
}
#ds-thread #ds-reset .ds-post-button:hover {
color: white;
background: #DE594C;
}
#ds-thread #ds-reset .ds-post-button:active {
background: #d32;
}
#ds-smilies-tooltip ul.ds-smilies-tabs li a.ds-current {
color: white;
background: #d32;
box-shadow: none;
text-shadow: none;
font-weight: normal;
}
</style>
<% } %>

View File

@ -1,11 +1,8 @@
<% if (typeof(script) !== 'undefined' && script) { %>
<script>(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/<%= config.language ? config.language.split('-').join('_') : 'en' %>/sdk.js#xfbml=1&version=v2.8";
js.src = "//connect.facebook.net/<%= get_config('language', 'en').split('-').join('_') %>/sdk.js#xfbml=1&version=v2.8";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
<% } else { %>
<div class="fb-comments" data-width="100%" data-href="<%= page.permalink %>" data-num-posts="5"></div>
<% } %>
<div class="fb-comments" data-width="100%" data-href="<%= page.permalink %>" data-num-posts="5"></div>

View File

@ -1,17 +1,23 @@
<% if (typeof(script) !== 'undefined' && script) { %>
<link rel="stylesheet" href="https://imsun.github.io/gitment/style/default.css">
<script src="https://imsun.github.io/gitment/dist/gitment.browser.js"></script>
<script>
if (document.getElementById('comments')) {
var gitment = new Gitment({
owner: '<%= theme.comment.gitment.owner %>',
repo: '<%= theme.comment.gitment.repo %>',
oauth: {
client_id: '<%= theme.comment.gitment.client_id %>',
client_secret: '<%= theme.comment.gitment.client_secret %>',
},
})
gitment.render('comments')
}
</script>
<% if (!has_config('comment.owner') || !has_config('comment.repo') || !has_config('comment.client_id') ||
!has_config('comment.client_secret')) { %>
<div class="notification is-danger">
You forgot to set the <code>owner</code>, <code>repo</code>, <code>client_id</code>, or <code>client_secret</code> for Gitment.
Please set it in <code>_config.yml</code>.
</div>
<% } else { %>
<div id="comment-container"></div>
<link rel="stylesheet" href="https://imsun.github.io/gitment/style/default.css">
<script src="https://imsun.github.io/gitment/dist/gitment.browser.js"></script>
<script>
var gitment = new Gitment({
id: '<%= page.path %>',
owner: '<%= get_config('comment.owner') %>',
repo: '<%= get_config('comment.repo') %>',
oauth: {
client_id: '<%= get_config('comment.client_id') %>',
client_secret: '<%= get_config('comment.client_secret') %>',
},
})
gitment.render('comment-container')
</script>
<% } %>

View File

@ -1,28 +0,0 @@
<% if (post.comments) { %>
<% if (theme.comment.disqus) { %>
<section id="comments"><%- partial('comment/disqus') %></section>
<% } else if (theme.comment.duoshuo) { %>
<section id="comments"><%- partial('comment/duoshuo') %></section>
<% } else if (theme.comment.youyan) { %>
<section id="comments"><%- partial('comment/youyan') %></section>
<% } else if (theme.comment.facebook) { %>
<section id="comments"><%- partial('comment/facebook') %></section>
<% } else if (theme.comment.isso) { %>
<section id="comments"><%- partial('comment/isso') %></section>
<% } else if (theme.comment.changyan && theme.comment.changyan.appid && theme.comment.changyan.conf) { %>
<section id="comments"><%- partial('comment/changyan') %></section>
<% } else if (theme.comment.livere) { %>
<section id="comments"><%- partial('comment/livere') %></section>
<% } else if (theme.comment.valine &&
theme.comment.valine.on &&
theme.comment.valine.appId &&
theme.comment.valine.appKey) { %>
<section id="comments"><%- partial('comment/valine') %></section>
<% } else if (theme.comment.gitment &&
theme.comment.gitment.owner &&
theme.comment.gitment.repo &&
theme.comment.gitment.client_id &&
theme.comment.gitment.client_secret) { %>
<section id="comments"><%- partial('comment/gitment') %></section>
<% } %>
<% } %>

View File

@ -1,8 +1,10 @@
<% if (typeof(script) !== 'undefined' && script) { %>
<script data-isso="//<%= theme.comment.isso %>"
src="//<%= theme.comment.isso %>/js/embed.min.js">
</script>
<% if (!has_config('comment.url')) { %>
<div class="notification is-danger">
You forgot to set the <code>url</code> for Isso. Please set it in <code>_config.yml</code>.
</div>
<% } else { %>
<section id="isso-thread"></section>
<div id="isso-thread"></div>
<script data-isso="//<%= get_config('comment.url') %>" src="//<%= get_config('comment.url') %>/js/embed.min.js">
</script>
<% } %>

View File

@ -1,22 +1,22 @@
<% if (typeof(script) !== 'undefined' && script) { %>
<!-- 来必力City版安装代码 -->
<script type="text/javascript">
(function(d, s) {
var j, e = d.getElementsByTagName(s)[0];
if (typeof LivereTower === 'function') { return; }
j = d.createElement(s);
j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
j.async = true;
e.parentNode.insertBefore(j, e);
})(document, 'script');
</script>
<noscript> 为正常使用来必力评论功能请激活JavaScript</noscript>
<!-- City版安装代码已完成 -->
<% if (!has_config('comment.uid')) { %>
<div class="notification is-danger">
You forgot to set the <code>uid</code> for LiveRe. Please set it in <code>_config.yml</code>.
</div>
<% } else { %>
<div id="lv-container" data-id="city" data-uid=<%= theme.comment.livere %>></div>
<div id="lv-container" data-id="city" data-uid="<%= get_config('comment.uid') %>">
<script type="text/javascript">
(function(d, s) {
var j, e = d.getElementsByTagName(s)[0];
if (typeof LivereTower === 'function') { return; }
j = d.createElement(s);
j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
j.async = true;
e.parentNode.insertBefore(j, e);
})(document, 'script');
</script>
<noscript> Please activate JavaScript for write a comment in LiveRe</noscript>
</div>
<% } %>

View File

@ -1,26 +0,0 @@
<% if (theme.comment.disqus) { %>
<%- partial('comment/disqus', { script: true }) %>
<% } else if (theme.comment.duoshuo) { %>
<%- partial('comment/duoshuo', { script: true }) %>
<% } else if (theme.comment.youyan) { %>
<%- partial('comment/youyan', { script: true }) %>
<% } else if (theme.comment.facebook) { %>
<%- partial('comment/facebook', { script: true }) %>
<% } else if (theme.comment.isso) { %>
<%- partial('comment/isso', { script: true }) %>
<% } else if (theme.comment.changyan && theme.comment.changyan.appid && theme.comment.changyan.conf) { %>
<%- partial('comment/changyan', { script: true }) %>
<% } else if (theme.comment.gitment &&
theme.comment.gitment.owner &&
theme.comment.gitment.repo &&
theme.comment.gitment.client_id &&
theme.comment.gitment.client_secret) { %>
<%- partial('comment/gitment', { script: true }) %>
<% } else if (theme.comment.livere) { %>
<%- partial('comment/livere', { script: true }) %>
<% } else if (theme.comment.valine &&
theme.comment.valine.on &&
theme.comment.valine.appId &&
theme.comment.valine.appKey) { %>
<%- partial('comment/valine', { script: true }) %>
<% } %>

View File

@ -1,16 +1,19 @@
<% if (typeof(script) !== 'undefined' && script) { %>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="//cdn.jsdelivr.net/gh/xcss/valine@v1.1.6/dist/Valine.min.js"></script>
<script>
new Valine({
el: '#valine-thread' ,
notify:<%= theme.comment.valine.notify %>,
verify:<%= theme.comment.valine.verify %>,
app_id: '<%= theme.comment.valine.appId %>',
app_key: '<%= theme.comment.valine.appKey %>',
placeholder: '<%= theme.comment.valine.placeholder %>'
});
</script>
<% if (!has_config('comment.app_id') || !has_config('comment.app_key')) { %>
<div class="notification is-danger">
You forgot to set the <code>app_id</code> or <code>app_key</code> for Valine. Please set it in <code>_config.yml</code>.
</div>
<% } else { %>
<div id="valine-thread"></div>
<div id="valine-thread"></div>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src='//unpkg.com/valine/dist/Valine.min.js'></script>
<script>
new Valine({
el: '#valine-thread' ,
notify: <%= get_config('comment.notify') %>,
verify: <%= get_config('comment.verify') %>,
app_id: '<%= get_config('comment.app_id') %>',
app_key: '<%= get_config('comment.app_key') %>',
placeholder: '<%= get_config('comment.placeholder') %>'
});
</script>
<% } %>

View File

@ -1,5 +0,0 @@
<% if (typeof(script) !== 'undefined' && script) { %>
<script type="text/javascript" src="http://v2.uyan.cc/code/uyan.js?uid=<%= theme.comment.youyan %>"></script>
<% } else { %>
<div id="uyan_frame"></div>
<% } %>

View File

@ -1,47 +1,103 @@
<article id="<%= post.layout %>-<%= post.slug %>" class="article article-type-<%= post.layout %><%= (post.direction && post.direction.toLowerCase() === 'rtl' ? ' rtl' : '') %>" itemscope itemprop="blogPost">
<div class="article-inner">
<% if (post.banner) { %>
<%- partial('post/banner') %>
<% } %>
<% if (post.link || post.title) { %>
<header class="article-header">
<%- partial('post/title', { class_name: 'article-title' }) %>
<% if (post.layout != 'page') { %>
<div class="article-meta">
<%- partial('post/date', { class_name: 'article-date', date_format: null }) %>
<%- partial('post/category') %>
<%- partial('post/tag') %>
</div>
<% } %>
</header>
<% } %>
<%- partial('post/gallery') %>
<div class="article-entry" itemprop="articleBody">
<% if (index && post.excerpt) { %>
<p><%- post.excerpt %></p>
<p class="article-more-link">
<a href="<%- url_for(post.path) %>#more"><%= __('article.more') %></a>
</p>
<% } else { %>
<% if (!index && post.toc) { %>
<div id="toc" class="toc-article">
<strong class="toc-title"><%= __('article.catalogue') %></strong>
<%- toc(post.content) %>
</div>
<% } %>
<%- post.content %>
<% } %>
</div>
<footer class="article-footer">
<%- partial('share/index', { post: post }) %>
<%- partial('comment/counter', { post: post }) %>
</footer>
<div class="card">
<% if (has_thumbnail(post)) { %>
<div class="card-image">
<%- index ? '<a href="' + url_for(post.link ? post.link : post.path) + '"' : '<span ' %> class="image is-7by1">
<img class="thumbnail" src="<%= get_thumbnail(post) %>" alt="<%= post.title %>">
<%- index ? '</a>' : '</span>' %>
</div>
<% if (!index) { %>
<%- partial('post/nav') %>
<% } %>
</article>
<div class="card-content article <%= post.hasOwnProperty('direction') ? post.direction : '' %>">
<% if (post.layout != 'page') { %>
<div class="level article-meta is-size-7 is-uppercase is-mobile is-overflow-x-auto">
<div class="level-left">
<time class="level-item has-text-grey" datetime="<%= date_xml(post.date) %>"><%= date(post.date) %></time>
<% if (post.categories && post.categories.length) { %>
<div class="level-item">
<%- list_categories(post.categories, {
class: 'has-link-grey ',
show_count: false,
style: 'none',
separator: '&nbsp;/&nbsp;'
}) %>
</div>
<% } %>
<% if (!has_config('article.readtime') || get_config('article.readtime') === true) { %>
<span class="level-item has-text-grey">
<% const words = word_count(post._content); %>
<% const time = duration((words / 150.0) * 60, 'seconds') %>
<%= `${ time.locale(get_config('language', 'en')).humanize() } ${ __('article.read')} (${ __('article.about') } ${ words } ${ __('article.words') })` %>
</span>
<% } %>
</div>
</div>
<% } %>
<h1 class="title is-size-3 is-size-4-mobile has-text-weight-normal">
<% if (index) { %>
<a class="has-link-black-ter" href="<%- url_for(post.link ? post.link : post.path) %>"><%= post.title %></a>
<% } else { %>
<%= post.title %>
<% } %>
</h1>
<div class="content">
<%- index && post.excerpt ? post.excerpt : post.content %>
</div>
<% if (!index && post.tags && post.tags.length) { %>
<div class="level is-size-7 is-uppercase">
<div class="level-start">
<div class="level-item">
<span class="is-size-6 has-text-grey has-mr-7">#</span>
<%- list_tags(post.tags, {
class: 'has-link-grey ',
show_count: false,
style: 'link'
}) %>
</div>
</div>
</div>
<% } %>
<% if (index && post.excerpt) { %>
<div class="level is-mobile">
<div class="level-start">
<div class="level-item">
<a class="button is-size-7 is-light" href="<%- url_for(post.path) %>#more"><%= __('article.more') %></a>
</div>
</div>
</div>
<% } %>
<% if (!index && has_config('share.type')) { %>
<%- partial('share/' + get_config('share.type')) %>
<% } %>
</div>
</div>
<% if (!index) { %>
<%- partial('comment/index') %>
<% if (!index && (post.prev || post.next)) { %>
<div class="card card-transparent">
<div class="level post-navigation is-flex-wrap is-mobile">
<% if (post.prev){ %>
<div class="level-start">
<a class="level level-item has-link-grey <%= !post.prev ? 'is-hidden-mobile' : '' %> article-nav-prev" href="<%- url_for(post.prev.path) %>">
<i class="level-item material-icons">keyboard_arrow_left</i>
<span class="level-item"><%= post.prev.title %></span>
</a>
</div>
<% } %>
<% if (post.next){ %>
<div class="level-end">
<a class="level level-item has-link-grey <%= !post.next ? 'is-hidden-mobile' : '' %> article-nav-next" href="<%- url_for(post.next.path) %>">
<span class="level-item"><%= post.next.title %></span>
<i class="level-item material-icons">keyboard_arrow_right</i>
</a>
</div>
<% } %>
</div>
</div>
<% } %>
<% if (!index && has_config('comment.type')) { %>
<div class="card">
<div class="card-content">
<h3 class="title is-5 has-text-weight-normal"><%= __('article.comments') %></h3>
<%- partial('comment/' + get_config('comment.type')) %>
</div>
</div>
<% } %>

View File

@ -1,8 +1,39 @@
<footer id="footer">
<div class="outer">
<div id="footer-info" class="inner">
&copy; <%= date(new Date(), 'YYYY') %> <%= config.author || config.title %><br>
Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>. Theme by <a href="http://github.com/ppoffice">PPOffice</a>
<footer class="footer">
<div class="container">
<div class="level">
<div class="level-start has-text-centered-mobile">
<a class="footer-logo is-block has-mb-6" href="<%- url_for('/') %>">
<% if (has_config('logo.text') && get_config('logo.text')) { %>
<%= get_config('logo.text') %>
<% } else { %>
<img src="<%- url_for(get_config('logo')) %>" alt="" height="28">
<% } %>
</a>
<p class="is-size-7">
&copy; <%= date(new Date(), 'YYYY') %> <%= get_config('author') || get_config('title') %>&nbsp;
Powered by <a href="http://hexo.io/" target="_blank">Hexo</a> & <a
href="http://github.com/ppoffice/hexo-theme-icarus">Icarus</a>
</p>
</div>
<div class="level-end">
<% if (has_config('footer.links')) { %>
<div class="field has-addons is-flex-center-mobile has-mt-5-mobile is-flex-wrap is-flex-middle">
<% let links = get_config('footer.links'); %>
<% for (let name in links) {
let link = links[name]; %>
<p class="control">
<a class="button is-white <%= typeof(link) !== 'string' ? 'is-large' : '' %>" target="_blank" title="<%= name %>" href="<%= url_for(typeof(link) === 'string' ? link : link.url) %>">
<% if (typeof(link) === 'string') { %>
<%= name %>
<% } else { %>
<i class="<%= link.icon %>"></i>
<% } %>
</a>
</p>
<% } %>
</div>
<% } %>
</div>
</div>
</div>
</footer>

View File

@ -1,50 +1,35 @@
<!DOCTYPE html>
<html<%= config.language ? " lang=" + config.language.substring(0, 2) : ""%>>
<head>
<meta charset="utf-8">
<%
function capitalize (str) { return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase() }
var title = page.title;
if (is_archive()) {
title = capitalize(__('index.archive'));
if (is_month()) {
title += ': ' + page.year + '/' + page.month;
} else if (is_year()) {
title += ': ' + page.year;
}
} else if (is_category()) {
title = capitalize(__('index.category')) + ': ' + page.category;
} else if (is_tag()) {
title = capitalize(__('index.tag')) + ': ' + page.tag;
}
%>
<title><% if (title) { %><%= title %> | <% } %><%= config.title %></title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<meta charset="utf-8">
<title><%= page_title() %></title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<%- meta(page) %>
<% if (has_config('open_graph')) { %>
<%- open_graph({
image: thumbnail(page),
fb_app_id: theme.miscellaneous.open_graph.fb_app_id,
fb_admins: theme.miscellaneous.open_graph.fb_admins,
twitter_id: theme.miscellaneous.open_graph.twitter_id,
google_plus: theme.miscellaneous.open_graph.google_plus,
twitter_id: get_config('open_graph.twitter_id'),
twitter_site: get_config('open_graph.twitter_site'),
google_plus: get_config('open_graph.google_plus'),
fb_admins: get_config('open_graph.fb_admins'),
fb_app_id: get_config('open_graph.fb_app_id')
}) %>
<%- meta(page) %>
<% } %>
<% if (theme.customize && theme.customize.social_links && theme.customize.social_links.rss) { %>
<link rel="alternate" href="<%- theme.customize.social_links.rss %>" title="<%= config.title %>" type="application/atom+xml" />
<% if (has_config('rss')) { %>
<link rel="alternative" href="<%- get_config('rss') %>" title="<%= get_config('title') %>" type="application/atom+xml">
<% } %>
<% if (has_config('favicon')) { %>
<link rel="icon" href="<%- url_for(get_config('favicon')) %>">
<% } %>
<%- css(cdn('bulma', '0.7.2', 'css/bulma.css')) %>
<%- css(iconcdn()) %>
<%- css(iconcdn('material')) %>
<%- css(fontcdn('Ubuntu:400,600|Source+Code+Pro')) %>
<%- css(cdn('highlight.js', '9.12.0', 'styles/' + get_config('article.highlight') + '.min.css')) %>
<%- css('css/style') %>
<% if (has_config('plugins')) { %>
<% for (let plugin in get_config('plugins')) { %>
<%- partial('plugin/' + plugin, { head: true, plugin: get_config('plugins')[plugin] }) %>
<% } %>
<% if (theme.customize.favicon) { %>
<link rel="icon" href="<%- url_for(theme.customize.favicon) %>" />
<% } %>
<%- css('libs/font-awesome5/css/fontawesome.min') %>
<%- css('libs/font-awesome5/css/fa-brands.min') %>
<%- css('libs/font-awesome5/css/fa-solid.min') %>
<%- css('libs/open-sans/styles') %>
<%- css('libs/source-code-pro/styles') %>
<%- css('css/style') %>
<%- js('libs/jquery/2.1.3/jquery.min') %>
<%- partial('plugin/scripts', { isHead: true }) %>
</head>
<% } %>

View File

@ -1,39 +0,0 @@
<header id="header">
<div id="header-main" class="header-inner">
<div class="outer">
<a href="<%- url_for() %>" id="logo">
<%- (theme.customize.logo && theme.customize.logo.enabled ? '<i class="logo"></i>':'') %>
<span class="site-title"><%= config.title %></span>
</a>
<nav id="main-nav">
<% for (var i in theme.menu) { %>
<a class="main-nav-link" href="<%- url_for(theme.menu[i]) %>"><%= i %></a>
<% } %>
</nav>
<% if(theme.customize.profile && theme.customize.profile.enabled) { %>
<% var profile = theme.customize.profile; %>
<nav id="sub-nav">
<div class="profile" id="profile-nav">
<a id="profile-anchor" href="javascript:;">
<img class="avatar" src="<%= ( profile.gravatar ? gravatar(profile.gravatar) : url_for(profile.avatar)) %>" />
<i class="fas fa-caret-down"></i>
</a>
</div>
</nav>
<% } %>
<%- partial('search/index') %>
</div>
</div>
<div id="main-nav-mobile" class="header-sub header-inner">
<table class="menu outer">
<tr>
<% for (var i in theme.menu) { %>
<td><a class="main-nav-link" href="<%- url_for(theme.menu[i]) %>"><%= i %></a></td>
<% } %>
<td>
<%- partial('search/index-mobile') %>
</td>
</tr>
</table>
</div>
</header>

43
layout/common/navbar.ejs Normal file
View File

@ -0,0 +1,43 @@
<nav class="navbar navbar-main">
<div class="container">
<div class="navbar-brand is-flex-center">
<a class="navbar-item navbar-logo" href="<%- url_for('/') %>">
<% if (has_config('logo.text') && get_config('logo.text')) { %>
<%= get_config('logo.text') %>
<% } else { %>
<img src="<%- url_for(get_config('logo')) %>" alt="" height="28">
<% } %>
</a>
</div>
<div class="navbar-menu">
<% if (has_config('navbar.menu')) { %>
<div class="navbar-start">
<% for (let i in get_config('navbar.menu')) { let menu = get_config('navbar.menu')[i]; %>
<a class="navbar-item<% if (typeof(page.path) !== 'undefined' && is_same_link(menu, page.path)) { %> is-active<% } %>"
href="<%- url_for(menu) %>"><%= i %></a>
<% } %>
</div>
<% } %>
<div class="navbar-end">
<% if (has_config('navbar.links')) { %>
<% let links = get_config('navbar.links'); %>
<% for (let name in links) {
let link = links[name]; %>
<a class="navbar-item" target="_blank" title="<%= name %>" href="<%= url_for(typeof(link) === 'string' ? link : link.url) %>">
<% if (typeof(link) === 'string') { %>
<%= name %>
<% } else { %>
<i class="<%= link.icon %>"></i>
<% } %>
</a>
<% } %>
<% } %>
<% if (has_config('search.type')) { %>
<a class="navbar-item search" title="<%= __('search.search') %>" href="javascript:;">
<i class="material-icons is-size-5">search</i>
</a>
<% } %>
</div>
</div>
</div>
</nav>

View File

@ -0,0 +1,48 @@
<% function link_url(i) {
return url_for(i === 1 ? page.base : page.base + get_config('pagination_dir') + '/' + i + '/');
}
function pagination(c, m) {
var current = c,
last = m,
delta = 1,
left = current - delta,
right = current + delta + 1,
range = [],
elements = [],
l;
for (let i = 1; i <= last; i++) {
if (i == 1 || i == last || i >= left && i < right) {
range.push(i);
}
}
for (let i of range) {
if (l) {
if (i - l === 2) {
elements.push(`<li><a class="pagination-link has-text-black-ter" href="${ link_url(l + 1) }">${ l + 1 }</a></li>`);
} else if (i - l !== 1) {
elements.push(`<li><span class="pagination-ellipsis has-text-black-ter">&hellip;</span></li>`);
}
}
elements.push(`<li><a class="pagination-link${ c === i ? ' is-current' : ' has-text-black-ter'}" href="${ link_url(i) }">${ i }</a></li>`);
l = i;
}
return elements;
} %>
<div class="card card-transparent">
<nav class="pagination is-centered" role="navigation" aria-label="pagination">
<div class="pagination-previous<%= page.current > 1 ? '' : ' is-invisible is-hidden-mobile' %>">
<a class="is-flex-grow has-text-black-ter" href="<%= link_url(page.current - 1) %>"><%= __('common.prev') %></a>
</div>
<div class="pagination-next<%= page.current < page.total ? '' : ' is-invisible is-hidden-mobile' %>">
<a class="is-flex-grow has-text-black-ter" href="<%= link_url(page.current + 1) %>"><%= __('common.next') %></a>
</div>
<ul class="pagination-list is-hidden-mobile">
<% pagination(page.current, page.total).forEach(element => { %>
<%- element %>
<% }) %>
</ul>
</nav>
</div>

View File

@ -1,14 +0,0 @@
<% if (post.link) { %>
<a href="<%- url_for(post.link) %>" target="_blank" itemprop="url">
<img src="<%- post.banner %>" class="article-banner" />
</a>
<% } else if (post.title) { %>
<% if (index) { %>
<a href="<%- url_for(post.path) %>" itemprop="url">
<img src="<%- post.banner %>" class="article-banner" />
</a>
<% } else { %>
<img src="<%- post.banner %>" class="article-banner" />
<% } %>
<% } %>

View File

@ -1,11 +0,0 @@
<% if (post.categories && post.categories.length) { %>
<div class="article-category">
<i class="fas fa-folder"></i>
<%- list_categories(post.categories, {
show_count: false,
class: 'article-category',
style: 'none',
separator: '<i class="fas fa-angle-right"></i>'
}) %>
</div>
<% } %>

View File

@ -1,8 +0,0 @@
<% if (post.date) { %>
<div class="<%= class_name %>">
<i class="fas fa-calendar-alt"></i>
<a href="<%- url_for(post.path) %>">
<time datetime="<%= date_xml(post.date) %>" itemprop="datePublished"><%= date(post.date, date_format) %></time>
</a>
</div>
<% } %>

View File

@ -1,9 +0,0 @@
<% if (post.photos && post.photos.length) { %>
<div class="article-gallery">
<% post.photos.forEach(function(photo, i) { %>
<a class="gallery-item" href="<%- url_for(photo) %>" rel="gallery_<%= post._id %>">
<img src="<%- url_for(photo) %>" itemprop="image" />
</a>
<% }) %>
</div>
<% } %>

View File

@ -1,22 +0,0 @@
<% if (post.prev || post.next) { %>
<nav id="article-nav">
<% if (post.prev) { %>
<a href="<%- url_for(post.prev.path) %>" id="article-nav-newer" class="article-nav-link-wrap">
<strong class="article-nav-caption"><%= __('nav.newer') %></strong>
<div class="article-nav-title">
<% if (post.prev.title) { %>
<%= post.prev.title %>
<% } else { %>
(no title)
<% } %>
</div>
</a>
<% } %>
<% if (post.next) { %>
<a href="<%- url_for(post.next.path) %>" id="article-nav-older" class="article-nav-link-wrap">
<strong class="article-nav-caption"><%= __('nav.older') %></strong>
<div class="article-nav-title"><%= post.next.title %></div>
</a>
<% } %>
</nav>
<% } %>

View File

@ -1,6 +0,0 @@
<% if (post.tags && post.tags.length) { %>
<div class="article-tag">
<i class="fas fa-tag"></i>
<%- list_tags(post.tags, { show_count: false, style: 'link' }) %>
</div>
<% } %>

View File

@ -1,15 +0,0 @@
<% if (post.link) { %>
<h1 itemprop="name">
<a class="<%= class_name %>" href="<%- url_for(post.link) %>" target="_blank" itemprop="url"><%= post.title %></a>
</h1>
<% } else if (post.title) { %>
<% if (index) { %>
<h1 itemprop="name">
<a class="<%= class_name %>" href="<%- url_for(post.path) %>"><%= post.title %></a>
</h1>
<% } else { %>
<h1 class="<%= class_name %>" itemprop="name">
<%= post.title %>
</h1>
<% } %>
<% } %>

View File

@ -1,39 +0,0 @@
<% var profile = theme.customize.profile; %>
<% var tagCount = site.tags.filter(function(tag) { return tag.length; }).length; %>
<aside id="profile" class="<%= (theme.customize.profile.fixed ? 'profile-fixed' : '') %>">
<div class="inner profile-inner">
<div class="base-info profile-block">
<img id="avatar" src="<%= ( profile.gravatar ? gravatar(profile.gravatar, 128) : url_for(profile.avatar)) %>" />
<h2 id="name"><%= profile.author %></h2>
<h3 id="title"><%= profile.author_title %></h3>
<span id="location"><i class="fas fa-map-marker-alt" style="padding-right: 5px"></i><%= profile.location %></span>
<a id="follow" target="_blank" href="<%= profile.follow %>"><%= __('profile.follow') %></a>
</div>
<div class="article-info profile-block">
<div class="article-info-block">
<%= site.posts.length %>
<span><%= (site.posts.length > 1 ? __('profile.posts') : __('profile.post')) %></span>
</div>
<div class="article-info-block">
<%= tagCount %>
<span><%= (tagCount > 1 ? __('profile.tags') : __('profile.tag')) %></span>
</div>
</div>
<% if(theme.customize.social_links) { %>
<div class="profile-block social-links">
<table>
<tr>
<% var tooltipClass = theme.customize.social_link_tooltip === false ? '' : 'class=tooltip'; %>
<% for(var i in theme.customize.social_links) { %>
<td>
<a href="<%- url_for(theme.customize.social_links[i]) %>" target="_blank" title="<%= i %>" <%= tooltipClass %>>
<i class="fab fa-<%= i %>"></i>
</a>
</td>
<% } %>
</tr>
</table>
</div>
<% } %>
</div>
</aside>

View File

@ -1,5 +1,11 @@
<%- partial('comment/scripts', { page: page }) %>
<%- partial('plugin/scripts') %>
<%- js(cdn('jquery', '3.3.1', 'jquery.min.js')) %>
<%- js(cdn('moment.js', '2.22.2', 'moment-with-locales.min.js')) %>
<script>moment.locale("<%= get_config('language', 'en') %>");</script>
<!-- Custom Scripts -->
<%- js('js/main') %>
<% if (has_config('plugins')) { %>
<% for (let plugin in get_config('plugins')) { %>
<%- partial('plugin/' + plugin, { head: false, plugin: get_config('plugins')[plugin] }) %>
<% } %>
<% } %>
<%- js('js/main') %>

View File

@ -1,8 +0,0 @@
<% if (Array.isArray(theme.widgets) && theme.widgets.length > 0) { %>
<aside id="sidebar">
<% theme.widgets.forEach(function(widget) { %>
<%- partial('widget/' + widget) %>
<% }) %>
<div id="toTop" class="fas fa-angle-up"></div>
</aside>
<% } %>

View File

@ -1,8 +0,0 @@
<a href="<%- url_for((post.link ? post.link : post.path)) %>" class="thumbnail">
<% var thumbnailUrl = thumbnail(post) %>
<% if (thumbnailUrl) { %>
<span style="background-image:url(<%= thumbnailUrl %>)" alt="<%= post.title %>" class="thumbnail-image"></span>
<% } else { %>
<span class="thumbnail-image thumbnail-none"></span>
<% } %>
</a>

View File

@ -1,39 +0,0 @@
<%
switch (type) {
case 'category':
title = page.category;
icon = 'folder';
break;
case 'tag':
title = '#' + page.tag;
icon = 'tag';
break;
}
%>
<div class="timeline timeline-wrap">
<div class="timeline-row timeline-row-major">
<span class="node"><i class="fas fa-<%= icon %>"></i></span>
<h1 class="title"><%= title %></h1>
</div>
<% page.posts.each(function (post, i) { %>
<div class="timeline-row">
<span class="node"></span>
<div class="content">
<%- partial('post/title', { post: post, index: true, class_name: 'timeline-article-title' }) %>
<div class="article-meta">
<%- partial('post/date', { post: post, class_name: 'article-date', date_format: null }) %>
<%- partial('post/category', { post: post }) %>
<%- partial('post/tag', { post: post }) %>
</div>
</div>
</div>
<% }); %>
</div>
<% if (page.total > 1) { %>
<nav id="page-nav">
<%- paginator({
prev_text: '&laquo; ' + __('nav.prev'),
next_text: __('nav.next') + ' &raquo;'
}) %>
</nav>
<% } %>

29
layout/common/widget.ejs Normal file
View File

@ -0,0 +1,29 @@
<% if (get_widgets(position).length) { %>
<% function side_column_class() {
switch (column_count()) {
case 2:
return 'is-4-tablet is-4-desktop is-4-widescreen';
case 3:
return 'is-4-tablet is-4-desktop is-3-widescreen';
}
return '';
} %>
<% function visibility_class() {
if (column_count() === 3 && position === 'right') {
return 'is-hidden-touch is-hidden-desktop-only';
}
return '';
} %>
<div class="column <%= position === 'left' ? 'has-order-1' : 'has-order-3' %> <%= side_column_class() %> <%= visibility_class() %>">
<% get_widgets(position).forEach(widget => {%>
<%- partial('widget/' + widget.type, { widget, post: page }) %>
<% }) %>
<% if (position === 'left') { %>
<div class="card card-transparent is-hidden-widescreen">
<% get_widgets('right').forEach(widget => {%>
<%- partial('widget/' + widget.type, { widget, post: page }) %>
<% }) %>
</div>
<% } %>
</div>
<% } %>

View File

@ -1,11 +1,6 @@
<% page.posts.each(function(post) { %>
<%- partial('common/article', { post: post, index: true }) %>
<% });
if (page.total > 1) { %>
<nav id="page-nav">
<%- paginator({
prev_text: '&laquo; ' + __('nav.prev'),
next_text: __('nav.next') + ' &raquo;'
}) %>
</nav>
<% page.posts.each(function(post){ %>
<%- partial('common/article', { post, index: true }) %>
<% }); %>
<% if (page.total > 1) { %>
<%- partial('common/paginator') %>
<% } %>

View File

@ -1,18 +1,35 @@
<%- partial('common/head') %>
<body>
<div id="container">
<%- partial('common/header') %>
<div class="outer">
<% if (theme.customize.profile.enabled) { %>
<%- partial('common/profile', null, {cache: !config.relative_link}) %>
<% } %>
<section id="main"><%- body %></section>
<% if (theme.customize.sidebar) { %>
<%- partial('common/sidebar', null, {cache: !config.relative_link}) %>
<% } %>
<!DOCTYPE html>
<html <%- has_config('language') ? ' lang="' + get_config('language').substring(0, 2) + '"' : '' %>>
<head>
<%- partial('common/head') %>
</head>
<body class="is-<%= column_count() %>-column">
<%- partial('common/navbar', { page }) %>
<% function main_column_class() {
switch (column_count()) {
case 1:
return 'is-12';
case 2:
return 'is-8-tablet is-8-desktop is-8-widescreen';
case 3:
return 'is-8-tablet is-8-desktop is-6-widescreen'
}
return '';
} %>
<section class="section">
<div class="container">
<div class="columns main">
<div class="column <%= main_column_class() %> has-order-2"><%- body %></div>
<%- partial('common/widget', { position: 'left' }) %>
<%- partial('common/widget', { position: 'right' }) %>
</div>
</div>
<%- partial('common/footer', null, {cache: !config.relative_link}) %>
<%- partial('common/scripts') %>
</div>
</section>
<%- partial('common/footer') %>
<%- partial('common/scripts') %>
<% if (has_config('search.type')) { %>
<%- partial('search/' + get_config('search.type')) %>
<% } %>
</body>
</html>

43
layout/plugin/animejs.ejs Normal file
View File

@ -0,0 +1,43 @@
<% if (plugin !== false) { %>
<% if (head) { %>
<style>body{opacity: 0}</style>
<% } else { %>
<%- js(cdn('animejs', '2.2.0', 'anime.js')) %>
<script>
function isIE() {
var ua = window.navigator.userAgent;
var msie = ua.indexOf('MSIE ');
var trident = ua.indexOf('Trident/');
return (msie > 0 || trident > 0);
}
$(document).ready(function () {
$('body').css('opacity', 1);
if (!isIE()) {
['.main > .column:first-child .card',
'.main > .column:nth-child(2) .card',
'.main > .column:last-child .card'].map(function(target) {
anime({
targets: target,
scale: [0.8, 1],
opacity: [0, 1],
duration: 300,
easing: 'easeOutSine',
delay: function(el, i, l) {
return i * 100;
}
})
});
anime({
targets: '.navbar-main',
translateY: [-100, 0],
opacity: [0, 1],
duration: 300,
easing: 'easeOutSine'
});
}
});
</script>
<% } %>
<% } %>

View File

@ -0,0 +1,26 @@
<% if (plugin !== false) { %>
<% if (!head) { %>
<div id="back-to-top" class="is-flex is-flex-center is-hidden-tablet">
<i class="material-icons">keyboard_arrow_up</i>
<span class="is-size-7">
<%= __('plugin.backtotop') %></span>
</div>
<script>
$(document).ready(function () {
var lastScrollTop = 0;
$(window).scroll(function (event) {
var scrollTop = $(this).scrollTop();
if (scrollTop > lastScrollTop || scrollTop === 0) {
$('#back-to-top').removeClass('is-active');
} else {
$('#back-to-top').addClass('is-active');
}
lastScrollTop = scrollTop;
});
$('#back-to-top').on('click', function () {
$('body, html').animate({ scrollTop: 0 }, 400);
});
});
</script>
<% } %>
<% } %>

View File

@ -1,9 +1,11 @@
<% if (head && get_config_from_obj(plugin, 'tracking_id')) { %>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?<%= theme.plugins.baidu_analytics %>";
hm.src = "//hm.baidu.com/hm.js?<%= get_config_from_obj(plugin, 'tracking_id') %>";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<% } %>

21
layout/plugin/gallery.ejs Normal file
View File

@ -0,0 +1,21 @@
<% if (plugin !== false) { %>
<% if (head) { %>
<%- css(cdn('lightgallery', '1.6.8', 'css/lightgallery.min.css')) %>
<%- css(cdn('justifiedGallery', '3.7.0', 'css/justifiedGallery.min.css')) %>
<% } else { %>
<%- js(cdn('lightgallery', '1.6.8', 'js/lightgallery-all.min.js')) %>
<%- js(cdn('justifiedGallery', '3.7.0', 'js/jquery.justifiedGallery.min.js')) %>
<script>
(function ($) {
$(document).ready(function () {
if (typeof($.fn.lightGallery) === 'function') {
$('.article').lightGallery({ selector: '.gallery-item' });
}
if (typeof($.fn.justifiedGallery) === 'function') {
$('.justified-gallery').justifiedGallery();
}
});
})(jQuery);
</script>
<% } %>
<% } %>

View File

@ -1,10 +1,10 @@
<script type="text/javascript">
(function(i,s,o,g,r,a,m) {i['GoogleAnalyticsObject']=r;i[r]=i[r]||function() {
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
<% if (head && get_config_from_obj(plugin, 'tracking_id')) { %>
<script async src="https://www.googletagmanager.com/gtag/js?id=<%= get_config_from_obj(plugin, 'tracking_id') %>"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
ga('create', '<%= theme.plugins.google_analytics %>', 'auto');
ga('send', 'pageview');
</script>
gtag('config', '<%= get_config_from_obj(plugin, 'tracking_id') %>');
</script>
<% } %>

10
layout/plugin/mathjax.ejs Normal file
View File

@ -0,0 +1,10 @@
<% if (!head && plugin !== false) { %>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-MML-AM_CHTML"></script>
<script>
MathJax.Hub.Config({
"HTML-CSS": {matchFontHeight: false},
SVG: {matchFontHeight: false},
CommonHTML: {matchFontHeight: false}
});
</script>
<% } %>

View File

@ -0,0 +1,22 @@
<% if (plugin !== false) { %>
<% if (head) { %>
<%- css(cdn('outdated-browser', '1.1.5', 'outdatedbrowser.min.css')) %>
<% } else { %>
<div id="outdated">
<h6>Your browser is out-of-date!</h6>
<p>Update your browser to view this website correctly. <a id="btnUpdateBrowser" href="http://outdatedbrowser.com/">Update my browser now </a></p>
<p class="last"><a href="#" id="btnCloseUpdateBrowser" title="Close">&times;</a></p>
</div>
<%- js(cdn('outdated-browser', '1.1.5', 'outdatedbrowser.min.js')) %>
<script>
$(document).ready(function () {
// plugin function, place inside DOM ready function
outdatedBrowser({
bgColor: '#f25648',
color: '#ffffff',
lowerThan: 'flex'
})
});
</script>
<% } %>
<% } %>

View File

@ -1,38 +0,0 @@
<% if (typeof(isHead) !== 'undefined' && isHead) { %>
<% if (theme.plugins.lightgallery) { %>
<%- css('libs/lightgallery/css/lightgallery.min') %>
<% } %>
<% if (theme.plugins.justifiedgallery) { %>
<%- css('libs/justified-gallery/justifiedGallery.min') %>
<% } %>
<% if (theme.plugins.google_analytics) { %>
<%- partial('plugin/google-analytics') %>
<% } %>
<% if (theme.plugins.google_site_verification) { %>
<meta name="google-site-verification" content="<%= theme.plugins.google_site_verification %>" />
<% } %>
<% if (theme.plugins.baidu_analytics) { %>
<%- partial('plugin/baidu-analytics') %>
<% } %>
<% } else { %>
<% if (theme.plugins.lightgallery) { %>
<%- js('libs/lightgallery/js/lightgallery.min') %>
<%- js('libs/lightgallery/js/lg-thumbnail.min') %>
<%- js('libs/lightgallery/js/lg-pager.min') %>
<%- js('libs/lightgallery/js/lg-autoplay.min') %>
<%- js('libs/lightgallery/js/lg-fullscreen.min') %>
<%- js('libs/lightgallery/js/lg-zoom.min') %>
<%- js('libs/lightgallery/js/lg-hash.min') %>
<%- js('libs/lightgallery/js/lg-share.min') %>
<%- js('libs/lightgallery/js/lg-video.min') %>
<% } %>
<% if (theme.plugins.justifiedgallery) { %>
<%- js('libs/justified-gallery/jquery.justifiedGallery.min') %>
<% } %>
<% if (theme.plugins.mathjax) { %>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ['\\(','\\)']] } });
</script>
<%- js('https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML') %>
<% } %>
<% } %>

View File

@ -1,13 +1,29 @@
<form class="search-form" method="GET" action="https://www.baidu.com/s?">
<input name="wd" type="text" class="search-form-input" placeholder="<%= __('index.search') %>" />
<button type="submit" class="search-form-submit"></button>
</form>
<%- css('css/search') %>
<div class="searchbox">
<div class="searchbox-container">
<div class="searchbox-input-wrapper">
<form class="search-form">
<input name="wd" type="text" class="searchbox-input" placeholder="<%= __('search.hint') %>" />
<span class="searchbox-close searchbox-selectable"><i class="fa fa-times-circle"></i></span>
</form>
</div>
</div>
</div>
<script>
(function ($) {
$('.search-form').on('submit', function (e) {
var keyword = $('.search-form-input[name="wd"]').val();
window.location = 'https://www.baidu.com/s?wd=site:<%= config.url.replace(/http(s)*:\/\//, "") %> ' + keyword;
return false;
});
})(jQuery);
(function ($) {
$('.search-form').on('submit', function (e) {
var keyword = $('.searchbox-input[name="wd"]').val();
window.location = 'https://www.baidu.com/s?wd=site:<%= config.url.replace(/http(s)*:\/\//, "") %> ' + keyword;
return false;
});
})(jQuery);
(function (document, $) {
$(document).on('click', '.navbar-main .search', function () {
$('.searchbox').toggleClass('show');
}).on('click', '.searchbox .searchbox-mask', function () {
$('.searchbox').removeClass('show');
}).on('click', '.searchbox-close', function () {
$('.searchbox').removeClass('show');
});
})(document, jQuery);
</script>

View File

@ -0,0 +1,67 @@
<%- css('css/search') %>
<div class="searchbox google-cse-search">
<div class="searchbox-container">
<div class="searchbox-input-wrapper">
<input type="text" class="searchbox-input" placeholder="<%= __('search.hint') %>" />
<span class="searchbox-close searchbox-selectable"><i class="fa fa-times-circle"></i></span>
</div>
<% if (has_config('search.cx')) { %>
<div class="searchbox-result-wrapper">
<gcse:searchresults-only></gcse:searchresults-only>
</div>
<% } else { %>
<div class="notification is-danger">
It seems that you forget to set the <code>cx</code> value for the Google CSE. Please set it in <code>_config.yml</code>.
</div>
<% } %>
</div>
<% if (has_config('search.cx')) { %>
<script>
(function() {
var cx = '<%= get_config('search.cx') %>';
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = 'https://cse.google.com/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
})();
</script>
<% } %>
</div>
<script>
(function (document, $) {
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
$(document).on('click', '.navbar-main .search', function () {
$('.searchbox').toggleClass('show');
}).on('click', '.searchbox .searchbox-mask', function () {
$('.searchbox').removeClass('show');
}).on('click', '.searchbox-close', function () {
$('.searchbox').removeClass('show');
}).on('keydown', '.searchbox-input', debounce(function () {
var value = $(this).val();
try {
var element = google.search.cse.element.getElement('searchresults-only0');
if (value.trim() === '') {
element.clearAllResults();
} else {
element.execute(value);
}
} catch (e) {}
}, 300));
})(document, jQuery);
</script>

View File

@ -1,13 +0,0 @@
<% if (theme.search.insight) { %>
<div class="search-form">
<input type="text" class="ins-search-input search-form-input" placeholder="<%= __('index.search') %>" />
</div>
<% } else if (theme.search.swiftype) { %>
<div class="search-form">
<input type="text" class="st-default-search-input search-form-input" placeholder="<%= __('index.search') %>" />
</div>
<% } else if (theme.search.baidu) { %>
<%- partial('search/baidu') %>
<% } else { %>
<%- search_form({text: __('index.search')}) %>
<% } %>

View File

@ -1,19 +0,0 @@
<div id="search-form-wrap">
<% if (theme.search.insight) { %>
<form class="search-form">
<input type="text" class="ins-search-input search-form-input" placeholder="<%= __('index.search') %>" />
<button type="submit" class="search-form-submit"></button>
</form>
<%- partial('search/insight') %>
<% } else if (theme.search.swiftype) { %>
<form class="search-form">
<input type="text" class="st-default-search-input search-form-input" placeholder="<%= __('index.search') %>" />
<button type="submit" class="search-form-submit"></button>
</form>
<%- partial('search/swiftype') %>
<% } else if (theme.search.baidu) { %>
<%- partial('search/baidu') %>
<% } else { %>
<%- search_form({ button: ' ', text: __('index.search') }) %>
<% } %>
</div>

View File

@ -1,29 +1,29 @@
<div class="ins-search">
<div class="ins-search-mask"></div>
<div class="ins-search-container">
<div class="ins-input-wrapper">
<input type="text" class="ins-search-input" placeholder="<%= __('insight.hint') %>" />
<span class="ins-close ins-selectable"><i class="fas fa-times-circle"></i></span>
<div class="searchbox ins-search">
<div class="searchbox-container ins-search-container">
<div class="searchbox-input-wrapper">
<input type="text" class="searchbox-input ins-search-input" placeholder="<%= __('insight.hint') %>" />
<span class="searchbox-close ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
</div>
<div class="ins-section-wrapper">
<div class="searchbox-result-wrapper ins-section-wrapper">
<div class="ins-section-container"></div>
</div>
</div>
</div>
<script>
(function (window) {
var INSIGHT_CONFIG = {
TRANSLATION: {
POSTS: '<%= __("insight.posts") %>',
PAGES: '<%= __("insight.pages") %>',
CATEGORIES: '<%= __("insight.categories") %>',
TAGS: '<%= __("insight.tags") %>',
UNTITLED: '<%= __("insight.untitled") %>',
},
ROOT_URL: '<%= config.root %>',
CONTENT_URL: '<%- url_for("/content.json")%>',
};
window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
(function (window) {
var INSIGHT_CONFIG = {
TRANSLATION: {
POSTS: '<%= __("insight.posts") %>',
PAGES: '<%= __("insight.pages") %>',
CATEGORIES: '<%= __("insight.categories") %>',
TAGS: '<%= __("insight.tags") %>',
UNTITLED: '<%= __("insight.untitled") %>',
},
CONTENT_URL: '<%- url_for("/content.json")%>',
};
window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
</script>
<%- js('js/insight') %>
<%- js('js/insight') %>
<%- css('css/search') %>
<%- css('css/insight') %>

View File

@ -1,26 +0,0 @@
<script type="text/javascript">
(function(w,d,t,u,n,s,e) {w['SwiftypeObject']=n;w[n]=w[n]||function() {
(w[n].q=w[n].q||[]).push(arguments);};s=d.createElement(t);
e=d.getElementsByTagName(t)[0];s.async=1;s.src=u;e.parentNode.insertBefore(s,e);
})(window,document,'script','//s.swiftypecdn.com/install/v2/st.js','_st');
_st('install','<%= theme.search.swiftype %>','2.0.0');
</script>
<style>
.st-ui-injected-overlay-container,
.st-ui-injected-overlay-container *:not(select) {
font-family: inherit !important;
}
section.st-ui-content.st-search-results a.st-ui-result .st-ui-type-heading {
color: <%= theme.customize.theme_color %> !important;
}
.st-ui-injected-overlay-container .st-ui-header input[type="text"]:focus {
border-bottom: 2px solid <%= theme.customize.theme_color %>;
}
.st-ui-injected-overlay-container .st-ui-footer a.st-ui-pagination-link {
color: <%= theme.customize.theme_color %>;
}
.st-ui-injected-overlay-container .st-ui-footer a.st-ui-pagination-link span.st-ui-arrow {
border-color: <%= theme.customize.theme_color %>;
}
</style>

8
layout/share/addthis.ejs Normal file
View File

@ -0,0 +1,8 @@
<% if (!has_config('share.install_url')) { %>
<div class="notification is-danger">
You need to set <code>install_url</code> to use AddThis. Please set it in <code>_config.yml</code>.
</div>
<% } else { %>
<div class="addthis_inline_share_toolbox"></div>
<script type="text/javascript" src="<%= get_config('share.install_url') %>"></script>
<% } %>

View File

@ -1,52 +1,9 @@
<div class="a2a_kit a2a_default_style">
<a class="a2a_dd" href="https://www.addtoany.com/share">Share</a>
<span class="a2a_divider"></span>
<a class="a2a_button_facebook"></a>
<a class="a2a_button_twitter"></a>
<a class="a2a_button_google_plus"></a>
<a class="a2a_button_pinterest"></a>
<a class="a2a_button_tumblr"></a>
<!-- AddToAny BEGIN -->
<div class="a2a_kit a2a_kit_size_32 a2a_default_style">
<a class="a2a_dd" href="https://www.addtoany.com/share"></a>
<a class="a2a_button_facebook"></a>
<a class="a2a_button_twitter"></a>
<a class="a2a_button_google_plus"></a>
</div>
<script type="text/javascript" src="//static.addtoany.com/menu/page.js"></script>
<style>
.a2a_menu {
border-radius: 4px;
}
.a2a_menu a {
margin: 2px 0;
font-size: 14px;
line-height: 16px;
border-radius: 4px;
color: inherit !important;
font-family: 'Microsoft Yahei';
}
#a2apage_dropdown {
margin: 10px 0;
}
.a2a_mini_services {
padding: 10px;
}
a.a2a_i,
i.a2a_i {
width: 122px;
line-height: 16px;
}
a.a2a_i .a2a_svg,
a.a2a_more .a2a_svg {
width: 16px;
height: 16px;
line-height: 16px;
vertical-align: top;
background-size: 16px;
}
a.a2a_i {
border: none !important;
}
a.a2a_menu_show_more_less {
margin: 0;
padding: 10px 0;
line-height: 16px;
}
.a2a_mini_services:after{content:".";display:block;height:0;clear:both;visibility:hidden}
.a2a_mini_services{*+height:1%;}
</style>
<script async src="https://static.addtoany.com/menu/page.js"></script>
<!-- AddToAny END -->

View File

@ -1,34 +1,9 @@
<div class="bdsharebuttonbox">
<a href="#" class="bds_more" data-cmd="more">分享到:</a>
<a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
<a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
<a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
<a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
<a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
<a href="#" class="bds_more" data-cmd="more"></a>
<a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间"></a>
<a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a>
<a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博"></a>
<a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网"></a>
<a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信"></a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
.bdshare_popup_box {
border-radius: 4px;
border: #e1e1e1 solid 1px;
}
.bdshare-button-style0-16 a,
.bdshare-button-style0-16 .bds_more {
padding-left: 20px;
margin: 6px 10px 6px 0;
}
.bdshare_dialog_list a,
.bdshare_popup_list a,
.bdshare_popup_bottom a {
font-family: 'Microsoft Yahei';
}
.bdshare_popup_top {
display: none;
}
.bdshare_popup_bottom {
height: auto;
padding: 5px;
}
</style>
<script>window._bd_share_config = { "common": { "bdSnsKey": {}, "bdText": "", "bdMini": "2", "bdPic": "", "bdStyle": "0", "bdSize": "16" }, "share": {} }; with (document) 0[(getElementsByTagName('head')[0] || body).appendChild(createElement('script')).src = 'http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion=' + ~(-new Date() / 36e5)];</script>

Some files were not shown because too many files have changed in this diff Show More