refactor(*): all layout to jsx & rename dirs

pull/588/head
ppoffice 2019-12-24 00:36:39 -05:00
parent 4234234c6c
commit ade254e66e
97 changed files with 583 additions and 729 deletions

View File

@ -1,13 +1,80 @@
{
"extends": "hexo",
"root": true,
"extends": [
"hexo",
"plugin:react/recommended"
],
"settings": {
"node": {
"tryExtensions": [
".js",
".jsx",
".json"
]
},
"react": {
"version": "16.0"
}
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
"react/jsx-uses-vars": "error",
"indent": [
"error",
4,
{
"SwitchCase": 1
}
],
"node/no-extraneous-require": [
"error",
{
"allowModules": [
"inferno",
"inferno-create-element",
"hexo",
"hexo-util",
"hexo-log",
"hexo-pagination",
"cheerio",
"moment"
]
}
],
"react/no-unknown-property": [
"error",
{
"ignore": [
"class",
"onclick",
"onsubmit"
]
}
],
"react/react-in-jsx-scope": [
"off"
],
"react/prop-types": [
"off"
],
"react/display-name": [
"off"
],
"react/jsx-key": [
"off"
],
"react/jsx-no-target-blank": [
"error",
{
"allowReferrer": true
}
]
}
}

45
include/filter/locals.js Normal file
View File

@ -0,0 +1,45 @@
const createPostSchema = require('hexo/lib/models/post');
const createPageSchema = require('hexo/lib/models/page');
module.exports = hexo => {
const RESERVED_KEYS = {
post: Object.keys(createPostSchema(hexo).paths),
page: Object.keys(createPageSchema(hexo).paths)
};
function getExtraConfig(source, reservedKeys) {
const result = {};
for (const key in source) {
if (!key.startsWith('_') && !reservedKeys.includes(key) && typeof source[key] !== 'function') {
result[key] = source[key];
}
}
return result;
}
hexo.extend.filter.register('template_locals', locals => {
// inject helper functions
locals.helper = {};
const helpers = hexo.extend.helper.list();
for (const name in helpers) {
locals.helper[name] = helpers[name].bind(locals);
}
if (typeof locals.__ === 'function') {
locals.helper.__ = locals.__;
}
if (typeof locals._p === 'function') {
locals.helper._p = locals._p;
}
// site config already merged into theme config in hexo/lib/hexo/index.js#Hexo.prototype._generateLocals()
locals.config = Object.assign({}, Object.getPrototypeOf(locals).theme);
// merge page configs
if (locals.page.__post === true) {
Object.assign(locals.config, getExtraConfig(locals.page, RESERVED_KEYS.page));
} else if (locals.page.__page === true) {
Object.assign(locals.config, getExtraConfig(locals.page, RESERVED_KEYS.page));
}
return locals;
});
};

View File

@ -1,8 +1,8 @@
/**
* Category list page generator
*/
module.exports = function (hexo) {
hexo.extend.generator.register('categories', function (locals) {
module.exports = function(hexo) {
hexo.extend.generator.register('categories', locals => {
return {
path: 'categories/',
layout: ['categories'],
@ -11,4 +11,4 @@ module.exports = function (hexo) {
})
};
});
}
};

View File

@ -1,6 +1,6 @@
const pagination = require('hexo-pagination');
module.exports = function (hexo) {
module.exports = function(hexo) {
// ATTENTION: This will override the default category generator!
hexo.extend.generator.register('category', function(locals) {
const config = this.config;
@ -9,14 +9,14 @@ module.exports = function (hexo) {
function findParent(category) {
let parents = [];
if (category && category.hasOwnProperty('parent')) {
if (category && 'parent' in category) {
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){
return locals.categories.reduce((result, category) => {
const posts = category.posts.sort('-date');
const data = pagination(category.path, posts, {
perPage: perPage,
@ -27,8 +27,8 @@ module.exports = function (hexo) {
parents: findParent(category)
}
});
return result.concat(data);
}, []);
});
}
};

View File

@ -3,15 +3,15 @@ const util = require('hexo-util');
/**
* Insight search content.json generator.
*/
module.exports = function (hexo) {
hexo.extend.generator.register('insight', function (locals) {
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) {
.replace(/&#x([\da-fA-F]+);/g, (match, hex) => {
return String.fromCharCode(parseInt(hex, 16));
})
.replace(/&#([\d]+);/g, function (match, dec) {
.replace(/&#([\d]+);/g, (match, dec) => {
return String.fromCharCode(dec);
});
}
@ -20,14 +20,14 @@ module.exports = function (hexo) {
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),
@ -40,4 +40,4 @@ module.exports = function (hexo) {
data: JSON.stringify(site)
};
});
}
};

View File

@ -1,8 +1,8 @@
/**
* Tag list page generator
*/
module.exports = function (hexo) {
hexo.extend.generator.register('tags', function (locals) {
module.exports = function(hexo) {
hexo.extend.generator.register('tags', locals => {
return {
path: 'tags/',
layout: ['tags'],
@ -11,4 +11,4 @@ module.exports = function (hexo) {
})
};
});
}
};

View File

@ -20,9 +20,10 @@ const icon_providers = {
fontawesome: 'https://use.fontawesome.com/releases/v5.4.1/css/all.css'
};
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');
module.exports = function(hexo) {
hexo.extend.helper.register('cdn', function(_package, version, filename) {
let provider = this.config.provider && 'cdn' in this.config.provider ? this.config.provider.cdn : 'jsdelivr';
// cdn.js does not follow a GitHub npm style like jsdeliver and unpkg do. Patch it!
if (provider === 'cdnjs' || provider.startsWith('[cdnjs]')) {
if (provider.startsWith('[cdnjs]')) {
@ -40,8 +41,8 @@ module.exports = function (hexo) {
filename = filename.startsWith('outdatedbrowser/') ? filename.substr(16) : filename;
}
if (_package === 'highlight.js') {
filename = filename.endsWith('.css') && filename.indexOf('.min.') === -1 ?
filename.substr(0, filename.length - 4) + '.min.css' : filename;
filename = filename.endsWith('.css') && filename.indexOf('.min.') === -1
? filename.substr(0, filename.length - 4) + '.min.css' : filename;
}
if (_package === 'mathjax') {
filename = filename.startsWith('unpacked/') ? filename.substr(9) : filename;
@ -53,7 +54,7 @@ module.exports = function (hexo) {
_package = 'clipboard.js';
}
}
if (provider !== null && cdn_providers.hasOwnProperty(provider)) {
if (provider !== null && provider in cdn_providers) {
provider = cdn_providers[provider];
}
return provider.replace(/\${\s*package\s*}/gi, _package)
@ -61,24 +62,24 @@ module.exports = function (hexo) {
.replace(/\${\s*filename\s*}/gi, filename);
});
hexo.extend.helper.register('fontcdn', function (fontName, type = 'css') {
let provider = hexo.extend.helper.get('get_config').bind(this)('providers.fontcdn');
if (provider !== null && font_providers.hasOwnProperty(provider)) {
hexo.extend.helper.register('fontcdn', function(fontName, type = 'css') {
let provider = this.config.provider && 'fontcdn' in this.config.provider ? this.config.provider.fontcdn : 'google';
if (provider !== null && provider in font_providers) {
provider = font_providers[provider];
}
return provider.replace(/\${\s*fontname\s*}/gi, fontName)
.replace(/\${\s*type\s*}/gi, type);
});
hexo.extend.helper.register('iconcdn', function (provider = null) {
if (provider !== null && icon_providers.hasOwnProperty(provider)) {
hexo.extend.helper.register('iconcdn', function(provider = null) {
if (provider !== null && provider in icon_providers) {
provider = icon_providers[provider];
} else {
provider = hexo.extend.helper.get('get_config').bind(this)('providers.iconcdn');
if (provider !== null && icon_providers.hasOwnProperty(provider)) {
provider = this.config.provider && 'iconcdn' in this.config.provider ? this.config.provider.iconcdn : 'fontawesome';
if (provider !== null && provider in icon_providers) {
provider = icon_providers[provider];
}
}
return provider;
});
}
};

31
include/helper/page.js Normal file
View File

@ -0,0 +1,31 @@
/**
* Helper functions for page/post.
*
* @example
* <%- is_categories(page) %>
* <%- is_tags(page) %>
* <%- has_thumbnail(post) %>
* <%- get_thumbnail(post) %>
*/
module.exports = function(hexo) {
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;
});
hexo.extend.helper.register('has_thumbnail', function(post) {
const { article } = this.config;
if (article && article.thumbnail === false) {
return false;
}
return 'thumbnail' in post && post.thumbnail;
});
hexo.extend.helper.register('get_thumbnail', function(post) {
const { url_for, has_thumbnail } = this.helper;
return url_for(has_thumbnail.call(this, post) ? post.thumbnail : 'images/thumbnail.svg');
});
};

View File

@ -38,7 +38,7 @@ try {
}
} 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('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

@ -4,8 +4,8 @@ function checkDependency(name) {
try {
require.resolve(name);
return true;
} catch(e) {
logger.error(`Package ${name} is not installed.`)
} catch (e) {
logger.error(`Package ${name} is not installed.`);
}
return false;
}
@ -17,9 +17,9 @@ const missingDeps = [
'cheerio',
'hexo-util',
'hexo-log',
'hexo-pagination',
'hexo-pagination'
].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);
throw new Error();
}

View File

@ -7,4 +7,4 @@ logger.info(`=======================================
=============================================`);
=============================================`);

View File

@ -1,48 +0,0 @@
/**
* 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

@ -1,22 +0,0 @@
/**
* Helper functions for page/post.
*
* @example
* <%- has_thumbnail(post) %>
* <%- get_thumbnail(post) %>
*/
module.exports = function (hexo) {
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');
});
}

View File

@ -1,38 +0,0 @@
{
"extends": [
"../.eslintrc"
],
"settings": {
"node": {
"tryExtensions": [
".js",
".jsx",
".json"
]
}
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
}
},
"plugins": [
"react"
],
"rules": {
"react/jsx-uses-vars": "error",
"node/no-extraneous-require": [
"error",
{
"allowModules": [
"inferno",
"inferno-create-element",
"hexo-util",
"hexo-log",
"cheerio",
"moment"
]
}
]
}
}

View File

@ -1,15 +1,10 @@
'use strict';
const moment = require('moment');
const { Component, Fragment } = require('inferno');
const Paginator = require('./misc/paginator');
module.exports = class extends Component {
render() {
const { page } = this.props;
// TODO
const helper = {};
const config = {};
const { config, page, helper } = this.props;
const { url_for, __, has_thumbnail, get_thumbnail, date_xml, date } = helper;
const language = page.lang || page.language || config.language;
@ -17,40 +12,40 @@ module.exports = class extends Component {
function renderArticleList(posts, year, month = null) {
const time = moment([page.year, page.month ? page.month - 1 : null].filter(i => i !== null));
return <div className="card widget">
<div className="card-content">
<h3 className="tag is-link">{month === null ? year : time.locale(language).format('MMMM YYYY')}</h3>
<div className="timeline">
return <div class="card widget">
<div class="card-content">
<h3 class="tag is-link">{month === null ? year : time.locale(language).format('MMMM YYYY')}</h3>
<div class="timeline">
{posts.map(post => {
const categories = [];
post.categories.forEach((category, i) => {
categories.push(<a className="has-link-grey" href={category.url}>{category.name}</a>);
categories.push(<a class="has-link-grey" href={category.url}>{category.name}</a>);
if (i < post.categories.length - 1) {
categories.push('/');
}
});
return <article className="media">
{has_thumbnail(post) ? <a href={url_for((post.link || post.path))} className="media-left">
<p className="image is-64x64">
<img className="thumbnail" src={get_thumbnail(post)} alt={post.title || get_thumbnail(post)} />
return <article class="media">
{has_thumbnail(post) ? <a href={url_for(post.link || post.path)} class="media-left">
<p class="image is-64x64">
<img class="thumbnail" src={get_thumbnail(post)} alt={post.title || get_thumbnail(post)} />
</p>
</a> : null}
<div className="media-content">
<div className="content">
<time className="has-text-grey is-size-7 is-block is-uppercase"
datetime={date_xml(post.date)}>{date(post.date)}</time>
<a className="title has-link-black-ter is-size-6 has-text-weight-normal"
href={url_for((post.link || post.path))} >{post.title}</a>
<div className="level article-meta is-mobile">
<div className="level-left">
{categories.length ? <div className="level-item is-size-7 is-uppercase">
<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 class="title has-link-black-ter is-size-6 has-text-weight-normal"
href={url_for(post.link || post.path)} >{post.title}</a>
<div class="level article-meta is-mobile">
<div class="level-left">
{categories.length ? <div class="level-item is-size-7 is-uppercase">
{categories}
</div> : null}
</div>
</div>
</div>
</div>
</article>
</article>;
})}
</div>
</div>
@ -60,9 +55,9 @@ module.exports = class extends Component {
let articleList;
if (!page.year) {
const years = {};
page.posts.each(p => years[p.date.year()] = null);
page.posts.each(p => { years[p.date.year()] = null; });
articleList = Object.keys(years).sort((a, b) => b - a).map(year => {
let posts = page.posts.filter(p => p.date.year() == year);
const posts = page.posts.filter(p => p.date.year() === parseInt(year, 10));
return renderArticleList(posts, year, null);
});
} else {
@ -81,4 +76,4 @@ module.exports = class extends Component {
nextTitle={__('common.next')} /> : null}
</Fragment>;
}
}
};

View File

@ -1,14 +1,10 @@
'use strict';
const { Component } = require('inferno');
const Categories = require('./widget/categories');
module.exports = class extends Component {
render() {
const { site, page } = this.props;
// TODO
const helper = {};
const { site, page, helper } = this.props;
return <Categories site={site} page={page} helper={helper} />;
}
}
};

View File

@ -1,30 +1,26 @@
'use strict';
const { Component, Fragment } = require('inferno');
const Index = require('./index');
module.exports = class extends Component {
render() {
const { page } = this.props;
// TODO
const helper = {};
const { config, page, helper } = this.props;
const { url_for, _p } = helper;
return <Fragment>
<div className="card">
<div className="card-content">
<nav className="breadcrumb" aria-label="breadcrumbs">
<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.map(category => {
return <li><a href={url_for(category.path)}>{category.name}</a></li>
return <li><a href={url_for(category.path)}>{category.name}</a></li>;
})}
<li className="is-active"><a href="#" aria-current="page">{page.category}</a></li>
<li class="is-active"><a href="#" aria-current="page">{page.category}</a></li>
</ul>
</nav>
</div>
</div>
<Index {...this.props} />
<Index config={config} page={page} helper={helper} />
</Fragment>;
}
}
};

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,7 +5,7 @@ class ChangeYan extends Component {
render() {
const { appId, conf, path } = this.props;
if (!appId || !conf) {
return <div className="notification is-danger">
return <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>;

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,7 +5,7 @@ class Disqus extends Component {
render() {
const { shortname, disqusId, path, permalink } = this.props;
if (!shortname) {
return <div className="notification is-danger">
return <div class="notification is-danger">
You forgot to set the <code>shortname</code> for Disqus.
Please set it in <code>_config.yml</code>.
</div>;

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -14,7 +12,7 @@ class Facebook extends Component {
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));`;
return <Fragment>
<div className="fb-comments" data-width="100%" data-href={permalink} data-num-posts="5"></div>
<div class="fb-comments" data-width="100%" data-href={permalink} data-num-posts="5"></div>
<script dangerouslySetInnerHTML={{ __html: js }}></script>
</Fragment>;
}

View File

@ -1,5 +1,3 @@
'use strict';
const crypto = require('crypto');
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -20,7 +18,7 @@ class Gitalk extends Component {
} = this.props;
if (!id || !repo || !owner || !admin || !clientId || !clientSecret) {
return <div className="notification is-danger">
return <div class="notification is-danger">
You forgot to set the <code>owner</code>, <code>admin</code>, <code>repo</code>,
<code>client_id</code>, or <code>client_secret</code> for Gittalk.
Please set it in <code>_config.yml</code>.

View File

@ -1,5 +1,3 @@
'use strict';
const crypto = require('crypto');
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -15,7 +13,7 @@ class Gitment extends Component {
} = this.props;
if (!id || !repo || !owner || !clientId || !clientSecret) {
return <div className="notification is-danger">
return <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>.

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,7 +5,7 @@ class Isso extends Component {
render() {
const { url } = this.props;
if (!url) {
return <div className="notification is-danger">
return <div class="notification is-danger">
You forgot to set the <code>url</code> for Isso.
Please set it in <code>_config.yml</code>.
</div>;

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,7 +5,7 @@ class LiveRe extends Component {
render() {
const { uid } = this.props;
if (!uid) {
return <div className="notification is-danger">
return <div class="notification is-danger">
You forgot to set the <code>uid</code> for LiveRe.
Please set it in <code>_config.yml</code>.
</div>;

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,7 +5,7 @@ class Valine extends Component {
render() {
const { appId, appKey, notify, verify, placeholder } = this.props;
if (!appId || !appKey) {
return <div className="notification is-danger">
return <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>;
@ -21,7 +19,7 @@ class Valine extends Component {
placeholder: '${placeholder}'
});`;
return <Fragment>
<div id="valine-thread" className="content"></div>
<div id="valine-thread" class="content"></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 dangerouslySetInnerHTML={{ __html: js }}></script>

View File

@ -1,5 +1,3 @@
'use strict';
const moment = require('moment');
const { Component, Fragment } = require('inferno');
const Share = require('./share');
@ -25,27 +23,27 @@ module.exports = class extends Component {
return <Fragment>
{/* Main content */}
<div className="card">
<div class="card">
{/* Thumbnail */}
{has_thumbnail(page) ? <div className="card-image">
{index ? <a href={url_for(page.link || page.path || page.permalink)} className="image is-7by1">
<img className="thumbnail" src={get_thumbnail(page)} alt={page.title || get_thumbnail(page)} />
</a> : <span className="image is-7by1">
<img className="thumbnail" src={get_thumbnail(page)} alt={page.title || get_thumbnail(page)} />
{has_thumbnail(page) ? <div class="card-image">
{index ? <a href={url_for(page.link || page.path)} class="image is-7by1">
<img class="thumbnail" src={get_thumbnail(page)} alt={page.title || get_thumbnail(page)} />
</a> : <span class="image is-7by1">
<img class="thumbnail" src={get_thumbnail(page)} alt={page.title || get_thumbnail(page)} />
</span>}
</div> : null}
{/* Metadata */}
<div className={`card-content article${Object.prototype.hasOwnProperty.call(page, 'direction') ? ' ' + page.direction : ''}`}>
{page.layout !== 'page' ? <div className="level article-meta is-size-7 is-uppercase is-mobile is-overflow-x-auto">
<div className="level-left">
<div class={`card-content article${'direction' in page ? ' ' + page.direction : ''}`}>
{page.layout !== 'page' ? <div class="level article-meta is-size-7 is-uppercase is-mobile is-overflow-x-auto">
<div class="level-left">
{/* Date */}
<time className="level-item has-text-grey" datetime={date_xml(page.date)}>{date(page.date)}</time>
<time class="level-item has-text-grey" dateTime={date_xml(page.date)}>{date(page.date)}</time>
{/* Categories */}
{page.categories && page.categories.length ? <div className="level-item">
{page.categories && page.categories.length ? <div class="level-item">
{(() => {
const categories = [];
page.categories.forEach((category, i) => {
categories.push(<a className="has-link-grey" href={category.url}>{category.name}</a>);
categories.push(<a class="has-link-grey" href={category.url}>{category.name}</a>);
if (i < page.categories.length - 1) {
categories.push('/');
}
@ -54,7 +52,7 @@ module.exports = class extends Component {
})()}
</div> : null}
{/* Read time */}
{article && article.readtime && article.readtime === true ? <span className="level-item has-text-grey">
{article && article.readtime && article.readtime === true ? <span class="level-item has-text-grey">
{(() => {
const words = getWordCount(page._content);
const time = moment.duration((words / 150.0) * 60, 'seconds');
@ -62,36 +60,34 @@ module.exports = class extends Component {
})()}
</span> : null}
{/* Visitor counter */}
{plugins && plugins.busuanzi === true ? <span className="level-item has-text-grey" id="busuanzi_container_page_pv"
{plugins && plugins.busuanzi === true ? <span class="level-item has-text-grey" id="busuanzi_container_page_pv"
dangerouslySetInnerHTML={{
__html: _p('plugin.visit', '<i className="far fa-eye"></i><span id="busuanzi_value_page_pv">0</span>')
__html: _p('plugin.visit', '<i class="far fa-eye"></i>&nbsp;&nbsp;<span id="busuanzi_value_page_pv">0</span>')
}}></span> : null}
</div>
</div> : null}
{/* Title */}
<h1 className="title is-size-3 is-size-4-mobile has-text-weight-normal">
{index ? <a className="has-link-black-ter" href={url_for(page.link || page.path)}>{page.title}</a> : page.title}
<h1 class="title is-size-3 is-size-4-mobile has-text-weight-normal">
{index ? <a class="has-link-black-ter" href={url_for(page.link || page.path)}>{page.title}</a> : page.title}
</h1>
{/* Content/Excerpt */}
<div className="content">
{index && page.excerpt ? page.excerpt : page.content}
</div>
<div class="content" dangerouslySetInnerHTML={{ __html: index && page.excerpt ? page.excerpt : page.content }}></div>
{/* Tags */}
{!index && Array.isArray(page.tags) && page.tags.length ? <div className="level is-size-7 is-uppercase">
<div className="level-start">
<div className="level-item">
<span className="is-size-6 has-text-grey has-mr-7">#</span>
{!index && Array.isArray(page.tags) && page.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>
{page.tags.map(tag => {
return <a href="has-link-grey" rel="tag" href={url_for(tag.path)}>{tag.name}</a>;
return <a class="has-link-grey" rel="tag" href={url_for(tag.path)}>{tag.name}</a>;
})}
</div>
</div>
</div> : null}
{/* "Read more" button */}
{index && page.excerpt ? <div className="level is-mobile">
<div className="level-start">
<div className="level-item">
<a className="button is-size-7 is-light" href={`${url_for(page.path)}#more`}>{__('article.more')}</a>
{index && page.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(page.path)}#more`}>{__('article.more')}</a>
</div>
</div>
</div> : null}
@ -102,18 +98,18 @@ module.exports = class extends Component {
{/* Donate button */}
{!index ? <Donates config={config} helper={helper} /> : null}
{/* Post navigation */}
{!index && (page.prev || page.next) ? <div className="card card-transparent">
<div className="level post-navigation is-flex-wrap is-mobile">
{page.prev ? <div className="level-start">
<a className={`level level-item has-link-grey${!page.prev ? ' is-hidden-mobile' : ''} article-nav-prev`} href={url_for(page.prev.path)}>
<i className="level-item fas fa-chevron-left"></i>
<span className="level-item">{page.prev.title}</span>
{!index && (page.prev || page.next) ? <div class="card card-transparent">
<div class="level post-navigation is-flex-wrap is-mobile">
{page.prev ? <div class="level-start">
<a class={`level level-item has-link-grey${!page.prev ? ' is-hidden-mobile' : ''} article-nav-prev`} href={url_for(page.prev.path)}>
<i class="level-item fas fa-chevron-left"></i>
<span class="level-item">{page.prev.title}</span>
</a>
</div> : null}
{page.next ? <div className="level-end">
<a className={`level level-item has-link-grey${!page.next ? ' is-hidden-mobile' : ''} article-nav-next`} href={url_for(page.next.path)}>
<span className="level-item">{page.next.title}</span>
<i className="level-item fas fa-chevron-right"></i>
{page.next ? <div class="level-end">
<a class={`level level-item has-link-grey${!page.next ? ' is-hidden-mobile' : ''} article-nav-next`} href={url_for(page.next.path)}>
<span class="level-item">{page.next.title}</span>
<i class="level-item fas fa-chevron-right"></i>
</a>
</div> : null}
</div>

View File

@ -1,6 +1,4 @@
'use strict';
const logger = require('hexo-log');
const logger = require('hexo-log')();
const { Component } = require('inferno');
module.exports = class extends Component {
@ -12,15 +10,15 @@ module.exports = class extends Component {
return null;
}
return <div className="card">
<div className="card-content">
<h3 className="title is-5 has-text-weight-normal">{__('article.comments')}</h3>
return <div class="card">
<div class="card-content">
<h3 class="title is-5 has-text-weight-normal">{__('article.comments')}</h3>
{(() => {
try {
const Comment = require('../comment/' + comment.type);
return <Comment config={config} page={page} helper={helper} comment={comment} />;
} catch (e) {
logger.warn(`Icarus cannot load comment "${comment.type}"`);
logger.w(`Icarus cannot load comment "${comment.type}"`);
return null;
}
})()}

View File

@ -1,6 +1,4 @@
'use strict';
const logger = require('hexo-log');
const logger = require('hexo-log')();
const { Component } = require('inferno');
module.exports = class extends Component {
@ -11,10 +9,10 @@ module.exports = class extends Component {
if (!Array.isArray(donate) || !donate.length) {
return null;
}
return <div className="card">
<div className="card-content">
<h3 className="menu-label has-text-centered">{__('donate.title')}</h3>
<div className="buttons is-centered">
return <div class="card">
<div class="card-content">
<h3 class="menu-label has-text-centered">{__('donate.title')}</h3>
<div class="buttons is-centered">
{donate.map(service => {
const type = service.type;
if (typeof type === 'string') {
@ -22,7 +20,7 @@ module.exports = class extends Component {
const Donate = require('../donate/' + type);
return <Donate helper={helper} donate={service} />;
} catch (e) {
logger.warn(`Icarus cannot load donate button "${type}"`);
logger.w(`Icarus cannot load donate button "${type}"`);
}
}
return null;

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -17,29 +15,29 @@ class Footer extends Component {
visitorCounterTitle
} = this.props;
return <footer className="footer">
<div className="container">
<div className="level">
<div className="level-start has-text-centered-mobile">
<a className="footer-logo is-block has-mb-6" href={siteUrl}>
return <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={siteUrl}>
{logo && logo.text ? logo.text : <img src={logoUrl} alt={siteTitle} height="28" />}
</a>
<p className="is-size-7">
<p class="is-size-7">
<span dangerouslySetInnerHTML={{ __html: `&copy; ${siteYear} ${author || siteTitle}` }}></span>
Powered by <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a> &
&nbsp;&nbsp;Powered by <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a> &
<a href="https://github.com/ppoffice/hexo-theme-icarus" target="_blank" rel="noopener">Icarus</a>
{showVisitorCounter ? <br /> : null}
{showVisitorCounter ? <span id="busuanzi_container_site_uv"
dangerouslySetInnerHTML={{ __html: visitorCounterTitle }}></span> : null}
</p>
</div>
<div className="level-end">
{Object.keys(links).length ? <div className="field has-addons is-flex-center-mobile has-mt-5-mobile is-flex-wrap is-flex-middle">
<div class="level-end">
{Object.keys(links).length ? <div class="field has-addons is-flex-center-mobile has-mt-5-mobile is-flex-wrap is-flex-middle">
{Object.keys(links).map(name => {
const link = links[name];
return <p className="control">
<a className={`button is-white ${link.icon ? 'is-large' : ''}`} target="_blank" rel="noopener" title={name} href={link.url}>
{link.icon ? name : <i className={link.icon}></i>}
return <p class="control">
<a class={`button is-white ${link.icon ? 'is-large' : ''}`} target="_blank" rel="noopener" title={name} href={link.url}>
{link.icon ? <i class={link.icon}></i> : name}
</a>
</p>;
})}
@ -52,7 +50,7 @@ class Footer extends Component {
}
module.exports = cacheComponent(Footer, 'common.footer', props => {
const { config, helper } = this.props;
const { config, helper } = props;
const { url_for, _p, date } = helper;
const { logo, title, author, footer, plugins } = config;

View File

@ -1,86 +1,35 @@
'use strict';
const { Component } = require('inferno');
const MetaTags = require('../misc/meta');
const OpenGraph = require('../misc/open_graph');
const Plugins = require('./plugins');
function isArchivePage(page) {
return !!page.archive;
}
function isCategoriesPage(page) {
return !!page.__categories;
}
function isTagsPage(page) {
return !!page.__tags;
}
function isMonthPage(page, year, month) {
if (!isArchivePage(page)) {
return false;
}
if (year) {
if (month) {
return page.year === year && page.month === month;
}
return page.month === year;
}
return page.year && page.month;
}
function isYearPage(page, year) {
if (!isArchivePage(page)) {
return false;
}
if (year) {
return page.year === year;
}
return !!page.year;
}
function isCategoryPage(page, category) {
if (category) {
return page.category === category;
}
return !!page.category;
}
function isTagPage(page, tag) {
if (tag) {
return page.tag === tag;
}
return !!page.tag;
}
function getPageTitle(page, siteTitle, _p) {
function getPageTitle(page, siteTitle, helper) {
let title = page.title;
if (isArchivePage(page)) {
title = _p('common.archive', Infinity);
if (isMonthPage()) {
if (helper.is_archive()) {
title = helper._p('common.archive', Infinity);
if (helper.is_month()) {
title += ': ' + page.year + '/' + page.month;
} else if (isYearPage(page)) {
} else if (helper.is_year()) {
title += ': ' + page.year;
}
} else if (isCategoryPage()) {
title = _p('common.category', 1) + ': ' + page.category;
} else if (isTagPage()) {
title = _p('common.tag', 1) + ': ' + page.tag;
} else if (isCategoriesPage(page)) {
title = _p('common.category', Infinity);
} else if (isTagsPage(page)) {
title = _p('common.tag', Infinity);
} else if (helper.is_category()) {
title = helper._p('common.category', 1) + ': ' + page.category;
} else if (helper.is_tag()) {
title = helper._p('common.tag', 1) + ': ' + page.tag;
} else if (helper.is_categories()) {
title = helper._p('common.category', Infinity);
} else if (helper.is_tags()) {
title = helper._p('common.tag', Infinity);
}
return [title, siteTitle].filter(str => typeof (str) !== 'undefined' && str.trim() !== '').join(' - ');
return [title, siteTitle].filter(str => typeof str !== 'undefined' && str.trim() !== '').join(' - ');
}
module.exports = class extends Component {
render() {
const { env, site, config, helper, page } = this.props;
const { is_post, url_for, cdn, iconcdn, fontcdn } = helper;
const { url_for, cdn, iconcdn, fontcdn, is_post } = helper;
const {
url,
meta_generator = true,
@ -98,8 +47,8 @@ module.exports = class extends Component {
let hlTheme, images;
if (highlight && highlight.enable === false) {
hlTheme = null;
} else if (article && article.highlight && article.hightlight.theme) {
hlTheme = article.hightlight.theme;
} else if (article && article.highlight && article.highlight.theme) {
hlTheme = article.highlight.theme;
} else {
hlTheme = 'atom-one-light';
}
@ -127,10 +76,10 @@ module.exports = class extends Component {
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<MetaTags meta={meta} />
<title>{getPageTitle(page, config.title, _p)}</title>
<title>{getPageTitle(page, config.title, helper)}</title>
{open_graph ? <OpenGraph
type={is_post() ? 'article' : 'website'}
type={is_post(page) ? 'article' : 'website'}
title={page.title || config.title}
date={page.date}
updated={page.updated}
@ -154,7 +103,7 @@ module.exports = class extends Component {
<link rel="stylesheet" href={fontcdn('Ubuntu:400,600|Source+Code+Pro')} />
{hlTheme ? <link rel="stylesheet" href={cdn('highlight.js', '9.12.0', 'styles/' + hlTheme + '.css')} /> : null}
<Plugins site={site} config={config} helper={helper} page={page} head={true} />
<link rel="stylesheet" href={url_for('/css/style')} />
<link rel="stylesheet" href={url_for('/css/style.css')} />
</head>;
}
};

View File

@ -1,7 +1,6 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
const classname = require('../util/classname');
function isSameLink(a, b) {
function santize(url) {
@ -21,7 +20,7 @@ class Navbar extends Component {
logoUrl,
siteUrl,
siteTitle,
menus,
menu,
links,
showToc,
tocTitle,
@ -29,34 +28,34 @@ class Navbar extends Component {
searchTitle
} = this.props;
return <nav className="navbar navbar-main">
<div className="container">
<div className="navbar-brand is-flex-center">
<a className="navbar-item navbar-logo" href={siteUrl}>
return <nav class="navbar navbar-main">
<div class="container">
<div class="navbar-brand is-flex-center">
<a class="navbar-item navbar-logo" href={siteUrl}>
{logo && logo.text ? logo.text : <img src={logoUrl} alt={siteTitle} height="28" />}
</a>
</div>
<div className="navbar-menu">
{Object.keys(menus).length ? <div className="navbar-start">
{Object.keys(menus).map(name => {
const menu = menus[name];
return <a className={{ 'navbar-item': true, 'is-active': menu.active }} href={menu.url}>{name}</a>;
<div class="navbar-menu">
{Object.keys(menu).length ? <div class="navbar-start">
{Object.keys(menu).map(name => {
const item = menu[name];
return <a class={classname({ 'navbar-item': true, 'is-active': item.active })} href={item.url}>{name}</a>;
})}
</div> : null}
<div className="navbar-end">
<div class="navbar-end">
{Object.keys(links).length ? <Fragment>
{Object.keys(links).forEach(name => {
{Object.keys(links).map(name => {
const link = links[name];
return <a className="navbar-item" target="_blank" rel="noopener" title={name} href={link.url}>
{link.icon ? <i className={link.icon}></i> : name}
return <a class="navbar-item" target="_blank" rel="noopener" title={name} href={link.url}>
{link.icon ? <i class={link.icon}></i> : name}
</a>;
})}
</Fragment> : null}
{showToc ? <a className="navbar-item is-hidden-tablet catalogue" title={tocTitle} href="javascript:;">
<i className="fas fa-list-ul"></i>
{showToc ? <a class="navbar-item is-hidden-tablet catalogue" title={tocTitle} href="javascript:;">
<i class="fas fa-list-ul"></i>
</a> : null}
{showSearch ? <a className="navbar-item search" title={searchTitle} href="javascript:;">
<i className="fas fa-search"></i>
{showSearch ? <a class="navbar-item search" title={searchTitle} href="javascript:;">
<i class="fas fa-search"></i>
</a> : null}
</div>
</div>
@ -73,13 +72,13 @@ module.exports = cacheComponent(Navbar, 'common.navbar', props => {
const hasTocWidget = Array.isArray(widgets) && widgets.find(widget => widget.type === 'toc');
const showToc = (config.toc === true || page.toc) && hasTocWidget && ['page', 'post'].includes(page.layout);
const menus = {};
if (navbar && navbar.menus) {
const menu = {};
if (navbar && navbar.menu) {
const pageUrl = typeof page.path !== 'undefined' ? url_for(page.path) : '';
Object.keys(navbar.menus).forEach(name => {
const url = url_for(navbar.menus[name]);
Object.keys(navbar.menu).forEach(name => {
const url = url_for(navbar.menu[name]);
const active = isSameLink(url, pageUrl);
menus[name] = { url, active };
menu[name] = { url, active };
});
}
@ -99,7 +98,7 @@ module.exports = cacheComponent(Navbar, 'common.navbar', props => {
logoUrl: url_for(logo),
siteUrl: url_for('/'),
siteTitle: title,
menus,
menu,
links,
showToc,
tocTitle: _p('widget.catalogue', Infinity),

View File

@ -1,6 +1,4 @@
'use strict';
const logger = require('hexo-log');
const logger = require('hexo-log')();
const { Component, Fragment } = require('inferno');
module.exports = class extends Component {
@ -18,7 +16,7 @@ module.exports = class extends Component {
const Plugin = require('../plugin/' + name);
return <Plugin site={site} config={config} page={page} helper={helper} plugin={plugins[name]} head={head} />;
} catch (e) {
logger.warn(`Icarus cannot load plugin "${name}"`);
logger.w(`Icarus cannot load plugin "${name}"`);
return null;
}
})}

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const Plugins = require('./plugins');

View File

@ -1,6 +1,4 @@
'use strict';
const logger = require('hexo-log');
const logger = require('hexo-log')();
const { Component } = require('inferno');
module.exports = class extends Component {
@ -15,7 +13,7 @@ module.exports = class extends Component {
const Search = require('../search/' + search.type);
return <Search config={config} helper={helper} search={search} />;
} catch (e) {
logger.warn(`Icarus cannot load search "${search.type}"`);
logger.w(`Icarus cannot load search "${search.type}"`);
return null;
}
}

View File

@ -1,6 +1,4 @@
'use strict';
const logger = require('hexo-log');
const logger = require('hexo-log')();
const { Component } = require('inferno');
module.exports = class extends Component {
@ -15,7 +13,7 @@ module.exports = class extends Component {
const Share = require('../share/' + share.type);
return <Share config={config} page={page} helper={helper} share={share} />;
} catch (e) {
logger.warn(`Icarus cannot load share button "${share.type}"`);
logger.w(`Icarus cannot load share button "${share.type}"`);
return null;
}
}

View File

@ -1,15 +1,13 @@
'use strict';
const logger = require('hexo-log');
const logger = require('hexo-log')();
const { Component } = require('inferno');
const classname = require('../util/classname');
function formatWidgets(widgets) {
const result = {};
if (Array.isArray(widgets)) {
widgets.forEach(widget => {
if (Object.prototype.hasOwnProperty.call(widget, 'position')
&& (widget.position === 'left' || widget.position === 'right')) {
if (!Object.prototype.hasOwnProperty.call(result, widget.position)) {
if ('position' in widget && (widget.position === 'left' || widget.position === 'right')) {
if (!(widget.position in result)) {
result[widget.position] = [widget];
} else {
result[widget.position].push(widget);
@ -23,10 +21,10 @@ function formatWidgets(widgets) {
function getColumnCount(widgets) {
let count = 1;
const w = formatWidgets(widgets);
if (Object.prototype.hasOwnProperty.call(w, 'left') && w.left.length) {
if ('left' in w && w.left.length) {
count++;
}
if (Object.prototype.hasOwnProperty.call(w, 'right') && w.left.length) {
if ('right' in w && w.right.length) {
count++;
}
return count;
@ -54,7 +52,7 @@ function getColumnOrderClass(position) {
}
function isColumnSticky(config, position) {
return config.sidebar && config.sidebar[position] && config.sidebar[position].sticky === true;
return config.sidebar && position in config.sidebar && config.sidebar[position].sticky === true;
}
class Widgets extends Component {
@ -67,15 +65,15 @@ class Widgets extends Component {
return null;
}
return <div className={{
return <div class={classname({
'column': true,
['column-' + position]: true,
[getColumnSizeClass(columnCount)]: true,
[getColumnVisibilityClass(columnCount, position)]: true,
[getColumnOrderClass(position)]: true,
'is-sticky': isColumnSticky(config, position)
}}>
{widgets[position].map(widget => {
})}>
{widgets.map(widget => {
// widget type is not defined
if (!widget.type) {
return null;
@ -84,15 +82,15 @@ class Widgets extends Component {
const Widget = require('../widget/' + widget.type);
return <Widget site={site} helper={helper} config={config} page={page} widget={widget} />;
} catch (e) {
logger.warn(`Icarus cannot load widget "${widget.type}"`);
logger.w(`Icarus cannot load widget "${widget.type}"`);
}
return null;
})}
{position === 'left' ? <div className={{
{position === 'left' ? <div class={classname({
'column-right-shadow': true,
'is-hidden-widescreen': true,
'is-sticky': isColumnSticky(config, position)
}}></div> : null}
'is-sticky': isColumnSticky(config, 'right')
})}></div> : null}
</div>;
}
}

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,17 +5,17 @@ class Alipay extends Component {
render() {
const { title, qrcode, url_for } = this.props;
if (!qrcode) {
return <div className="notification is-danger">
return <div class="notification is-danger">
You forgot to set the <code>qrcode</code> for Alipay.
Please set it in <code>_config.yml</code>.
</div>;
}
return <a className="button is-info donate">
<span className="icon is-small">
<i className="fab fa-alipay"></i>
return <a class="button is-info donate">
<span class="icon is-small">
<i class="fab fa-alipay"></i>
</span>
<span>{title}</span>
<span className="qrcode"><img src={url_for(qrcode)} alt={title} /></span>
<span class="qrcode"><img src={url_for(qrcode)} alt={title} /></span>
</a>;
}
}

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,14 +5,14 @@ class Patreon extends Component {
render() {
const { title, url, url_for } = this.props;
if (!url) {
return <div className="notification is-danger">
return <div class="notification is-danger">
You forgot to set the <code>url</code> Patreon.
Please set it in <code>_config.yml</code>.
</div>;
}
return <a className="button is-danger donate" href={url_for(url)} target="_blank" rel="noopener">
<span className="icon is-small">
<i className="fab fa-patreon"></i>
return <a class="button is-danger donate" href={url_for(url)} target="_blank" rel="noopener">
<span class="icon is-small">
<i class="fab fa-patreon"></i>
</span>
<span>{title}</span>
</a>;

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,15 +5,15 @@ class Paypal extends Component {
render() {
const { title, business, currencyCode } = this.props;
if (!business || !currencyCode) {
return <div className="notification is-danger">
return <div class="notification is-danger">
You forgot to set the <code>business</code> or <code>currency_code</code> for Paypal.
Please set it in <code>_config.yml</code>.
</div>;
}
return <Fragment>
<a className="button is-warning donate" onclick="document.getElementById('paypal-donate-form').submit()">
<span className="icon is-small">
<i className="fab fa-paypal"></i>
<a class="button is-warning donate" onclick="document.getElementById('paypal-donate-form').submit()">
<span class="icon is-small">
<i class="fab fa-paypal"></i>
</span>
<span>{title}</span>
</a>

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,17 +5,17 @@ class Wechat extends Component {
render() {
const { title, qrcode, url_for } = this.props;
if (!qrcode) {
return <div className="notification is-danger">
return <div class="notification is-danger">
You forgot to set the <code>qrcode</code> for Wechat.
Please set it in <code>_config.yml</code>.
</div>;
}
return <a className="button is-info donate">
<span className="icon is-small">
<i className="fab fa-weixin"></i>
return <a class="button is-success donate">
<span class="icon is-small">
<i class="fab fa-weixin"></i>
</span>
<span>{title}</span>
<span className="qrcode"><img src={url_for(qrcode)} alt={title} /></span>
<span class="qrcode"><img src={url_for(qrcode)} alt={title} /></span>
</a>;
}
}

View File

@ -1,26 +1,22 @@
'use strict';
const { Component, Fragment } = require('inferno');
const Article = require('./common/article');
const Paginator = require('./misc/paginator');
module.exports = class extends Component {
render() {
const { page } = this.props;
// TODO
const helper = {};
const config = {};
const { config, page, helper } = this.props;
const { __, url_for } = helper;
return <Fragment>
{page.posts.each(post => <Article config={config} page={post} helper={helper} index={true} />)}
{page.posts.map(post => <Article config={config} page={post} helper={helper} index={true} />)}
{page.total > 1 ? <Paginator
current={page.current}
total={page.total}
baseUrl={page.base}
path={config.pagination_dir}
urlFor={helper.url_for}
prevTitle={helper.__('common.prev')}
nextTitle={helper.__('common.next')} /> : null}
urlFor={url_for}
prevTitle={__('common.prev')}
nextTitle={__('common.next')} /> : null}
</Fragment>;
}
}
};

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const Head = require('./common/head');
const Navbar = require('./common/navbar');
@ -7,13 +5,11 @@ const Widgets = require('./common/widgets');
const Footer = require('./common/footer');
const Scripts = require('./common/scripts');
const Search = require('./common/search');
const classname = require('./util/classname');
module.exports = class extends Component {
render() {
const { env, site, page, body } = this.props;
// TODO
const helper = {};
const config = {};
const { env, site, config, page, helper, body } = this.props;
const language = page.lang || page.language || config.language;
const columnCount = Widgets.getColumnCount(config.widgets);
@ -22,19 +18,19 @@ module.exports = class extends Component {
<head>
<Head env={env} site={site} config={config} helper={helper} page={page} />
</head>
<body className={`is-${columnCount}-column`}>
<body class={`is-${columnCount}-column`}>
<Navbar config={config} helper={helper} page={page} />
<section className="section">
<div className="container">
<div className="columns">
<div className={{
<section class="section">
<div class="container">
<div class="columns">
<div class={classname({
column: true,
'has-order-2': true,
'column-main': true,
'is-12': columnCount === 1,
'is-8-tablet is-8-desktop is-8-widescreen': columnCount === 2,
'is-8-tablet is-8-desktop is-6-widescreen': columnCount === 3
}} dangerouslySetInnerHTML={{ __html: body }}></div>
})} dangerouslySetInnerHTML={{ __html: body }}></div>
<Widgets site={site} config={config} helper={helper} page={page} position={'left'} />
<Widgets site={site} config={config} helper={helper} page={page} position={'right'} />
</div>
@ -46,4 +42,4 @@ module.exports = class extends Component {
</body>
</html>;
}
}
};

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
function trim(str) {

View File

@ -1,5 +1,3 @@
'use strict';
// adapted from hexo/lib/plugins/helper/open_graph.js
const urlFn = require('url');
const moment = require('moment');

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
module.exports = class extends Component {
@ -29,26 +27,26 @@ module.exports = class extends Component {
for (const i of range) {
if (l) {
if (i - l === 2) {
elements.push(<li><a className="pagination-link has-text-black-ter" href={getPageUrl(l + 1)}>{l + 1}</a></li>);
elements.push(<li><a class="pagination-link has-text-black-ter" href={getPageUrl(l + 1)}>{l + 1}</a></li>);
} else if (i - l !== 1) {
elements.push(<li><span className="pagination-ellipsis has-text-black-ter" dangerouslySetInnerHTML={{ __html: '&hellip;' }}></span></li>);
elements.push(<li><span class="pagination-ellipsis has-text-black-ter" dangerouslySetInnerHTML={{ __html: '&hellip;' }}></span></li>);
}
}
elements.push(<li><a className={`pagination-link${c === i ? ' is-current' : ' has-text-black-ter'}`} href={getPageUrl(i)}>{i}</a></li>);
elements.push(<li><a class={`pagination-link${c === i ? ' is-current' : ' has-text-black-ter'}`} href={getPageUrl(i)}>{i}</a></li>);
l = i;
}
return elements;
}
return <div className="card card-transparent">
<nav className="pagination is-centered" role="navigation" aria-label="pagination">
<div className={`pagination-previous${current > 1 ? '' : ' is-invisible is-hidden-mobile'}`}>
<a className="is-flex-grow has-text-black-ter" href={getPageUrl(current - 1)}>{prevTitle}</a>
return <div class="card card-transparent">
<nav class="pagination is-centered" role="navigation" aria-label="pagination">
<div class={`pagination-previous${current > 1 ? '' : ' is-invisible is-hidden-mobile'}`}>
<a class="is-flex-grow has-text-black-ter" href={getPageUrl(current - 1)}>{prevTitle}</a>
</div>
<div className={`pagination-next${current < total ? '' : ' is-invisible is-hidden-mobile'}`}>
<a className="is-flex-grow has-text-black-ter" href={getPageUrl(current + 1)}>{nextTitle}</a>
<div class={`pagination-next${current < total ? '' : ' is-invisible is-hidden-mobile'}`}>
<a class="is-flex-grow has-text-black-ter" href={getPageUrl(current + 1)}>{nextTitle}</a>
</div>
<ul className="pagination-list is-hidden-mobile">
<ul class="pagination-list is-hidden-mobile">
{pagination(current, total)}
</ul>
</nav>

View File

@ -1,15 +1,10 @@
'use strict';
const { Component } = require('inferno');
const Article = require('./common/article');
module.exports = class extends Component {
render() {
const { page } = this.props;
// TODO
const helper = {};
const config = {};
const { config, page, helper } = this.props;
return <Article config={config} page={page} helper={helper} index={false} />;
}
}
};

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -12,7 +10,7 @@ class BackToTop extends Component {
}
return <Fragment>
<a id="back-to-top" title={title} href="javascript:;">
<i className="fas fa-chevron-up"></i>
<i class="fas fa-chevron-up"></i>
</a>
<script src={url_for('/js/back-to-top.js')} defer={true}></script>
</Fragment>;

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -21,7 +19,7 @@ class Mathjax extends Component {
tex2jax: {
inlineMath: [
['$','$'],
['\\(','\\)']
['\\\\(','\\\\)']
]
}
});

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -25,7 +23,7 @@ class OutdatedBrowser extends Component {
Update your browser to view this website correctly.&npsb;
<a id="btnUpdateBrowser" href="http://outdatedbrowser.com/">Update my browser now </a>
</p>
<p className="last"><a href="#" id="btnCloseUpdateBrowser" title="Close">&times;</a></p>
<p class="last"><a href="#" id="btnCloseUpdateBrowser" title="Close">&times;</a></p>
</div>
<script src={jsUrl} async={true}></script>
<script dangerouslySetInnerHTML={{ __html: js }}></script>

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');

View File

@ -1,15 +1,10 @@
'use strict';
const { Component } = require('inferno');
const Article = require('./common/article');
module.exports = class extends Component {
render() {
const { page } = this.props;
// TODO
const helper = {};
const config = {};
const { config, page, helper } = this.props;
return <Article config={config} page={page} helper={helper} index={false} />;
}
}
};

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -26,12 +24,12 @@ class Baidu extends Component {
return <Fragment>
<link rel="stylesheet" href={url_for('/css/search.css')} />
<div className="searchbox">
<div className="searchbox-container">
<div className="searchbox-input-wrapper">
<form className="search-form">
<input name="wd" type="text" className="searchbox-input" placeholder={hint} />
<span className="searchbox-close searchbox-selectable"><i className="fa fa-times-circle"></i></span>
<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={hint} />
<span class="searchbox-close searchbox-selectable"><i class="fa fa-times-circle"></i></span>
</form>
</div>
</div>

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -54,18 +52,18 @@ class Google extends Component {
return <Fragment>
<link rel="stylesheet" href={url_for('/css/search.css')} />
<div className="searchbox google-cse-search">
<div className="searchbox-container">
<div className="searchbox-input-wrapper">
<input type="text" className="searchbox-input" placeholder={hint} />
<span className="searchbox-close searchbox-selectable"><i className="fa fa-times-circle"></i></span>
<div class="searchbox google-cse-search">
<div class="searchbox-container">
<div class="searchbox-input-wrapper">
<input type="text" class="searchbox-input" placeholder={hint} />
<span class="searchbox-close searchbox-selectable"><i class="fa fa-times-circle"></i></span>
</div>
{(() => {
if (cx) {
const innerHtml = '<gcse:searchresults-only></gcse:searchresults-only>';
return <div className="searchbox-result-wrapper" dangerouslySetInnerHTML={{ __html: innerHtml }}></div>;
return <div class="searchbox-result-wrapper" dangerouslySetInnerHTML={{ __html: innerHtml }}></div>;
}
return <div className="notification is-danger">
return <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>;

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -24,14 +22,14 @@ class Insight extends Component {
return <Fragment>
<link rel="stylesheet" href={url_for('/css/search.css')} />
<link rel="stylesheet" href={url_for('/css/insight.css')} />
<div className="searchbox ins-search">
<div className="searchbox-container ins-search-container">
<div className="searchbox-input-wrapper">
<input type="text" className="searchbox-input ins-search-input" placeholder={hint} />
<span className="searchbox-close ins-close ins-selectable"><i className="fa 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={hint} />
<span class="searchbox-close ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
</div>
<div className="searchbox-result-wrapper ins-section-wrapper">
<div className="ins-section-container"></div>
<div class="searchbox-result-wrapper ins-section-wrapper">
<div class="ins-section-container"></div>
</div>
</div>
</div>

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,13 +5,13 @@ class AddThis extends Component {
render() {
const { installUrl } = this.props;
if (!installUrl) {
return <div className="notification is-danger">
return <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>;
}
return <Fragment>
<div className="addthis_inline_share_toolbox"></div>
<div class="addthis_inline_share_toolbox"></div>
<script src={installUrl} async={true}></script>
</Fragment>;
}

View File

@ -1,18 +1,16 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
class AddToAny extends Component {
render() {
return <Fragment>
<div className="a2a_kit a2a_kit_size_32 a2a_default_style">
<a className="a2a_dd" href="https://www.addtoany.com/share"></a>
<a className="a2a_button_facebook"></a>
<a className="a2a_button_twitter"></a>
<a className="a2a_button_telegram"></a>
<a className="a2a_button_whatsapp"></a>
<a className="a2a_button_reddit"></a>
<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_telegram"></a>
<a class="a2a_button_whatsapp"></a>
<a class="a2a_button_reddit"></a>
</div>
<script src="https://static.addtoany.com/menu/page.js" async={true}></script>
</Fragment>;

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,13 +5,13 @@ class BdShare extends Component {
render() {
const js = '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)];';
return <Fragment>
<div className="bdsharebuttonbox">
<a href="#" className="bds_more" data-cmd="more"></a>
<a href="#" className="bds_qzone" data-cmd="qzone" title="分享到QQ空间"></a>
<a href="#" className="bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a>
<a href="#" className="bds_tqq" data-cmd="tqq" title="分享到腾讯微博"></a>
<a href="#" className="bds_renren" data-cmd="renren" title="分享到人人网"></a>
<a href="#" className="bds_weixin" data-cmd="weixin" title="分享到微信"></a>
<div class="bdsharebuttonbox">
<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 dangerouslySetInnerHTML={{ __html: js }}></script>
</Fragment>;

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -8,7 +6,7 @@ class ShareJs extends Component {
const { cssUrl, jsUrl } = this.props;
return <Fragment>
<link rel="stylesheet" href={cssUrl} />
<div className="social-share"></div>
<div class="social-share"></div>
<script src={jsUrl}></script>
</Fragment>;
}

View File

@ -1,5 +1,3 @@
'use strict';
const { Component, Fragment } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,13 +5,13 @@ class ShareThis extends Component {
render() {
const { installUrl } = this.props;
if (!installUrl) {
return <div className="notification is-danger">
return <div class="notification is-danger">
You need to set <code>install_url</code> to use ShareThis.
Please set it in <code>_config.yml</code>.
</div>;
}
return <Fragment>
<div className="sharethis-inline-share-buttons"></div>
<div class="sharethis-inline-share-buttons"></div>
<script src={installUrl} async={true}></script>
</Fragment>;
}

View File

@ -1,27 +1,23 @@
'use strict';
const { Component, Fragment } = require('inferno');
const Index = require('./index');
module.exports = class extends Component {
render() {
const { page } = this.props;
// TODO
const helper = {};
const { config, page, helper } = this.props;
const { url_for, _p } = helper;
return <Fragment>
<div className="card">
<div className="card-content">
<nav className="breadcrumb" aria-label="breadcrumbs">
<div class="card">
<div class="card-content">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li><a href={url_for('/tags')}>{_p('common.tag', Infinity)}</a></li>
<li className="is-active"><a href="#" aria-current="page">{page.tag}</a></li>
<li class="is-active"><a href="#" aria-current="page">{page.tag}</a></li>
</ul>
</nav>
</div>
</div>
<Index {...this.props} />
<Index config={config} page={page} helper={helper} />
</Fragment>;
}
}
};

View File

@ -1,14 +1,10 @@
'use strict';
const { Component } = require('inferno');
const Tags = require('./widget/tags');
module.exports = class extends Component {
render() {
const { site } = this.props;
// TODO
const helper = {};
const { site, helper } = this.props;
return <Tags site={site} helper={helper} />;
}
}
};

View File

@ -1,5 +1,3 @@
'use strict';
const crypto = require('crypto');
const { Component } = require('inferno'); // eslint-disable-line no-unused-vars
const { createElement } = require('inferno-create-element');

12
layout/util/classname.jsx Normal file
View File

@ -0,0 +1,12 @@
module.exports = function(classname) {
if (typeof classname === 'string') {
return classname;
}
if (Array.isArray(classname)) {
return classname.join(' ');
}
if (typeof classname === 'object') {
return Object.keys(classname).filter(key => !!classname[key]).join(' ');
}
throw new Error('Cannot process class name' + JSON.stringify(classname));
};

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -11,18 +9,18 @@ class Archives extends Component {
showCount
} = this.props;
return <div className="card widget">
<div className="card-content">
<div className="menu">
<h3 className="menu-label">{title}</h3>
<ul className="menu-list">
return <div class="card widget">
<div class="card-content">
<div class="menu">
<h3 class="menu-label">{title}</h3>
<ul class="menu-list">
{items.map(archive => <li>
<a className="level is-marginless" href={archive.url}>
<span className="level-start">
<span className="level-item">{archive.name}</span>
<a class="level is-marginless" href={archive.url}>
<span class="level-start">
<span class="level-item">{archive.name}</span>
</span>
{showCount ? <span className="level-end">
<span className="level-item tag">{archive.count}</span>
{showCount ? <span class="level-end">
<span class="level-item tag">{archive.count}</span>
</span> : null}
</a>
</li>)}

View File

@ -1,20 +1,18 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');
class Categories extends Component {
renderList(categories, showCount) {
return categories.map(category => <li>
<a className="level is-marginless" href={category.url}>
<span className="level-start">
<span className="level-item">{category.name}</span>
<a class="level is-marginless" href={category.url}>
<span class="level-start">
<span class="level-item">{category.name}</span>
</span>
{showCount ? <span className="level-end">
<span className="level-item tag">{category.count}</span>
{showCount ? <span class="level-end">
<span class="level-item tag">{category.count}</span>
</span> : null}
</a>
{category.children.length ? <ul>{this.renderList(category.children)}</ul> : null}
{category.children.length ? <ul>{this.renderList(category.children, showCount)}</ul> : null}
</li>);
}
@ -25,11 +23,11 @@ class Categories extends Component {
categories
} = this.props;
return <div className="card widget">
<div className="card-content">
<div className="menu">
<h3 className="menu-label">{title}</h3>
<ul className="menu-list">
return <div class="card widget">
<div class="card-content">
<div class="menu">
<h3 class="menu-label">{title}</h3>
<ul class="menu-list">
{this.renderList(categories, showCount)}
</ul>
</div>

View File

@ -1,5 +1,3 @@
'use strict';
const { URL } = require('url');
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,23 +5,23 @@ const { cacheComponent } = require('../util/cache');
class Links extends Component {
render() {
const { title, links } = this.props;
return <div className="card widget">
<div className="card-content">
<div className="menu">
<h3 className="menu-label">{title}</h3>
<ul className="menu-list">
return <div class="card widget">
<div class="card-content">
<div class="menu">
<h3 class="menu-label">{title}</h3>
<ul class="menu-list">
{Object.keys(links).map(i => {
let hostname = links[i];
try {
hostname = new URL(hostname).hostname;
} catch (e) { }
return <li>
<a className="level is-mobile" href="<%- links[i] %>" target="_blank" rel="noopener">
<span className="level-left">
<span className="level-item">{i}</span>
<a class="level is-mobile" href="<%- links[i] %>" target="_blank" rel="noopener">
<span class="level-left">
<span class="level-item">{i}</span>
</span>
<span className="level-right">
<span className="level-item tag">{hostname}</span>
<span class="level-right">
<span class="level-item tag">{hostname}</span>
</span>
</a>
</li>;

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const gravatrHelper = require('hexo-util').gravatar;
const { cacheComponent } = require('../util/cache');
@ -9,11 +7,11 @@ class Profile extends Component {
if (!links.length) {
return null;
}
return <div className="level is-mobile">
return <div class="level is-mobile">
{links.map(link => {
return <a className="level-item button is-white is-marginless"
return <a class="level-item button is-white is-marginless"
target="_blank" rel="noopener" title={link.name} href={link.url}>
{Object.prototype.hasOwnProperty.call(link, 'icon') ? <i className={link.icon}></i> : link.name}
{'icon' in link ? <i class={link.icon}></i> : link.name}
</a>;
})}
</div>;
@ -31,51 +29,51 @@ class Profile extends Component {
followTitle,
socialLinks
} = this.props;
return <div className="card widget">
<div className="card-content">
<nav className="level">
<div className="level-item has-text-centered" style="flex-shrink: 1">
return <div class="card widget">
<div class="card-content">
<nav class="level">
<div class="level-item has-text-centered" style="flex-shrink: 1">
<div>
<figure className="image is-128x128 has-mb-6">
<img className={avatarRounded ? 'is-rounded' : ''} src={avatar} alt={author} />
<figure class="image is-128x128 has-mb-6">
<img class={avatarRounded ? 'is-rounded' : ''} src={avatar} alt={author} />
</figure>
{author ? <p className="is-size-4 is-block">{author}</p> : null}
{authorTitle ? <p className="is-size-6 is-block">{authorTitle}</p> : null}
{location ? <p className="is-size-6 is-flex is-flex-center has-text-grey">
<i className="fas fa-map-marker-alt has-mr-7"></i>
{author ? <p class="is-size-4 is-block">{author}</p> : null}
{authorTitle ? <p class="is-size-6 is-block">{authorTitle}</p> : null}
{location ? <p class="is-size-6 is-flex is-flex-center has-text-grey">
<i class="fas fa-map-marker-alt has-mr-7"></i>
<span>{location}</span>
</p> : null}
</div>
</div>
</nav>
<nav className="level is-mobile">
<div className="level-item has-text-centered is-marginless">
<nav class="level is-mobile">
<div class="level-item has-text-centered is-marginless">
<div>
<p className="heading">{counter.post.title}</p>
<p class="heading">{counter.post.title}</p>
<a href={counter.post.url}>
<p className="title has-text-weight-normal">{counter.post.count}</p>
<p class="title has-text-weight-normal">{counter.post.count}</p>
</a>
</div>
</div>
<div className="level-item has-text-centered is-marginless">
<div class="level-item has-text-centered is-marginless">
<div>
<p className="heading">{counter.category.title}</p>
<p class="heading">{counter.category.title}</p>
<a href={counter.category.url}>
<p className="title has-text-weight-normal">{counter.category.count}</p>
<p class="title has-text-weight-normal">{counter.category.count}</p>
</a>
</div>
</div>
<div className="level-item has-text-centered is-marginless">
<div class="level-item has-text-centered is-marginless">
<div>
<p className="heading">{counter.tag.title}</p>
<p class="heading">{counter.tag.title}</p>
<a href={counter.tag.url}>
<p className="title has-text-weight-normal">{counter.tag.count}</p>
<p class="title has-text-weight-normal">{counter.tag.count}</p>
</a>
</div>
</div>
</nav>
{followLink ? <div className="level">
<a className="level-item button is-link is-rounded" href={followLink} target="_blank" rel="noopener">{followTitle}</a>
{followLink ? <div class="level">
<a class="level-item button is-link is-rounded" href={followLink} target="_blank" rel="noopener">{followTitle}</a>
</div> : null}
{this.renderSocialLinks(socialLinks)}
</div>

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,28 +5,28 @@ class RecentPosts extends Component {
render() {
const { title, thumbnail, posts } = this.props;
return <div className="card widget">
<div className="card-content">
<h3 className="menu-label">{title}</h3>
return <div class="card widget">
<div class="card-content">
<h3 class="menu-label">{title}</h3>
{posts.map(post => {
const categories = [];
post.categories.forEach((category, i) => {
categories.push(<a className="has-link-grey" href={category.url}>{category.name}</a>);
categories.push(<a class="has-link-grey" href={category.url}>{category.name}</a>);
if (i < post.categories.length - 1) {
categories.push('/');
}
});
return <article className="media">
{thumbnail ? <a href={post.url} className="media-left">
<p className="image is-64x64">
<img className="thumbnail" src={post.thumbnail} alt={post.title} />
return <article class="media">
{thumbnail ? <a href={post.url} class="media-left">
<p class="image is-64x64">
<img class="thumbnail" src={post.thumbnail} alt={post.title} />
</p>
</a> : null}
<div className="media-content">
<div className="content">
<div><time className="has-text-grey is-size-7 is-uppercase" datetime={post.dateXml}>{post.date}</time></div>
<a href={post.url} className="title has-link-black-ter is-size-6 has-text-weight-normal">{post.title}</a>
<p className="is-size-7 is-uppercase">{categories}</p>
<div class="media-content">
<div class="content">
<div><time class="has-text-grey is-size-7 is-uppercase" dateTime={post.dateXml}>{post.date}</time></div>
<a href={post.url} class="title has-link-black-ter is-size-6 has-text-weight-normal">{post.title}</a>
<p class="is-size-7 is-uppercase">{categories}</p>
</div>
</div>
</article>;
@ -46,7 +44,7 @@ module.exports = cacheComponent(RecentPosts, 'widget.recentposts', props => {
}
const thumbnail = config.article && config.article.thumbnail;
const posts = site.posts.sort('date', -1).limit(5).map(post => ({
url: url_for(post.permalink || post.link || post.path),
url: url_for(post.link || post.path),
title: post.title,
date: date(post.date),
dateXml: date_xml(post.date),

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -7,27 +5,27 @@ class SubscribeEmail extends Component {
render() {
const { title, description, feedburnerId, buttonTitle } = this.props;
return <div className="card widget">
<div className="card-content">
<div className="menu">
<h3 className="menu-label">{title}</h3>
return <div class="card widget">
<div class="card-content">
<div class="menu">
<h3 class="menu-label">{title}</h3>
<div>
<form action="https://feedburner.google.com/fb/a/mailverify" method="post" target="popupwindow"
onsubmit={`window.open('https://feedburner.google.com/fb/a/mailverify?uri=${feedburnerId}','popupwindow','scrollbars=yes,width=550,height=520');return true`}>
<input type="hidden" value={feedburnerId} name="uri" />
<input type="hidden" name="loc" value="en_US" />
<div className="field">
<div className="control has-icons-left">
<input className="input" name="email" type="email" />
<span className="icon is-small is-left">
<i className="fas fa-envelope"></i>
<div class="field">
<div class="control has-icons-left">
<input class="input" name="email" type="email" />
<span class="icon is-small is-left">
<i class="fas fa-envelope"></i>
</span>
</div>
<p className="help">{description}</p>
<p class="help">{description}</p>
</div>
<div className="field is-grouped is-grouped-right">
<div className="control">
<input className="button is-link" type="submit" value={buttonTitle} />
<div class="field is-grouped is-grouped-right">
<div class="control">
<input class="button is-link" type="submit" value={buttonTitle} />
</div>
</div>
</form>

View File

@ -1,5 +1,3 @@
'use strict';
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -11,15 +9,15 @@ class Tags extends Component {
showCount
} = this.props;
return <div className="card widget">
<div className="card-content">
<div className="menu">
<h3 className="menu-label">{title}</h3>
<div className="field is-grouped is-grouped-multiline">
{tags.map(tag => <div className="control">
<a className="tags has-addons" href={tag.url}>
<span className="tag">{tag.name}</span>
{showCount ? <span className="tag is-grey">{tag.count}</span> : null}
return <div class="card widget">
<div class="card-content">
<div class="menu">
<h3 class="menu-label">{title}</h3>
<div class="field is-grouped is-grouped-multiline">
{tags.map(tag => <div class="control">
<a class="tags has-addons" href={tag.url}>
<span class="tag">{tag.name}</span>
{showCount ? <span class="tag is-grey">{tag.count}</span> : null}
</a>
</div>)}
</div>

View File

@ -1,5 +1,3 @@
'use strict';
const cheerio = require('cheerio');
const { Component } = require('inferno');
const { cacheComponent } = require('../util/cache');
@ -63,7 +61,7 @@ function getToc(content) {
}
let node = toc;
for (const i of levels.slice(0, level + 1)) {
if (!Object.prototype.hasOwnProperty.call(node, i)) {
if (!(i in node)) {
node[i] = {};
}
node = node[i];
@ -85,16 +83,14 @@ class Toc extends Component {
.sort((a, b) => a - b);
if (keys.length > 0) {
result = <ul className="menu-list">
result = <ul class="menu-list">
{keys.map(i => this.renderToc(toc[i]))}
</ul>;
}
if (Object.prototype.hasOwnProperty.call(toc, 'id')
&& Object.prototype.hasOwnProperty.call(toc, 'index')
&& Object.prototype.hasOwnProperty.call(toc, 'text')) {
if ('id' in toc && 'index' in toc && 'text' in toc) {
result = <li>
<a className="is-flex" href={'#' + toc.id}>
<span className="has-mr-6">{toc.index}</span>
<a class="is-flex" href={'#' + toc.id}>
<span class="has-mr-6">{toc.index}</span>
<span>{toc.text}</span>
</a>
{result}
@ -109,10 +105,10 @@ class Toc extends Component {
return null;
}
return <div className="card widget" id="toc">
<div className="card-content">
<div className="menu">
<h3 className="menu-label">{this.props.title}</h3>
return <div class="card widget" id="toc">
<div class="card-content">
<div class="menu">
<h3 class="menu-label">{this.props.title}</h3>
{this.renderToc(toc)}
</div>
</div>

View File

@ -10,7 +10,7 @@
"author": "ppoffice <zrp1994@gmail.com>",
"license": "MIT",
"scripts": {
"lint": "eslint .",
"lint": "eslint --ext .js --ext .jsx .",
"test": "mocha test/index.js",
"postpublish" : "PACKAGE_VERSION=$(cat package.json | grep \\\"version\\\" | head -1 | awk -F: '{ print $2 }' | sed 's/[\",]//g' | tr -d '[[:space:]]') && git tag $PACKAGE_VERSION && git push --tags"
},

View File

@ -1,19 +1,20 @@
require('../includes/tasks/welcome');
require('../includes/tasks/check_deps');
require('../includes/tasks/check_config');
require('../includes/generators/categories')(hexo);
require('../includes/generators/category')(hexo);
require('../includes/generators/tags')(hexo);
require('../includes/generators/insight')(hexo);
require('../includes/helpers/cdn')(hexo);
require('../includes/helpers/config')(hexo);
require('../includes/helpers/page')(hexo);
/* global hexo*/
require('../include/task/welcome');
require('../include/task/check_deps');
require('../include/task/check_config');
require('../include/generator/categories')(hexo);
require('../include/generator/category')(hexo);
require('../include/generator/tags')(hexo);
require('../include/generator/insight')(hexo);
require('../include/filter/locals')(hexo);
require('../include/helper/cdn')(hexo);
require('../include/helper/page')(hexo);
// Fix large blog rendering OOM
const hooks = [
'after_render:html',
'after_post_render'
]
];
const filters = [
'hexoMetaGeneratorInject',
'externalLinkFilter'
@ -25,6 +26,6 @@ hooks.forEach(hook => {
});
// Debug helper
hexo.extend.helper.register('console', function () {
console.log(arguments)
});
hexo.extend.helper.register('console', function() {
console.log(arguments);
});

View File

@ -1,4 +1,6 @@
(function ($) {
$('.columns .column-right-shadow').append($('.columns .column-right').children().clone());
$('.article img:not(".not-gallery-item")').each(function () {
// wrap images with link and add caption if possible
if ($(this).parent('a').length === 0) {