diff --git a/includes/common/ConfigGenerator.js b/includes/common/ConfigGenerator.js
index ab218be..961b09e 100644
--- a/includes/common/ConfigGenerator.js
+++ b/includes/common/ConfigGenerator.js
@@ -32,6 +32,28 @@ const YAML_SCHEMA = new Schema({
]
});
+function appendDoc(spec, defaults) {
+ if (defaults === null) {
+ return null;
+ }
+ if (is.array(defaults) && spec.hasOwnProperty('*')) {
+ return defaults.map(value => appendDoc(spec['*'], value));
+ } else if (is.object(defaults)) {
+ const _defaults = {};
+ for (let key in defaults) {
+ if (spec.hasOwnProperty(key) && spec[key].hasOwnProperty(doc)) {
+ let i = 0;
+ for (let line of spec[key][doc].split('\n')) {
+ _defaults['#' + key + i++] = line;
+ }
+ }
+ _defaults[key] = appendDoc(spec.hasOwnProperty(key) ? spec[key] : {}, defaults[key]);
+ }
+ return _defaults;
+ }
+ return defaults;
+}
+
function generate(spec, parentConfig = null) {
if (!is.spec(spec)) {
return UNDEFINED;
@@ -40,7 +62,7 @@ function generate(spec, parentConfig = null) {
return UNDEFINED;
}
if (spec.hasOwnProperty(defaultValue)) {
- return spec[defaultValue];
+ return appendDoc(spec, spec[defaultValue]);
}
const types = is.array(spec[type]) ? spec[type] : [spec[type]];
if (types.includes('object')) {
@@ -54,16 +76,10 @@ function generate(spec, parentConfig = null) {
if (defaults === UNDEFINED) {
defaults = {};
}
- if (spec[key].hasOwnProperty(doc)) {
- let i = 0;
- for (let line of spec[key][doc].split('\n')) {
- defaults['#' + key + i++] = line;
- }
- }
defaults[key] = value;
}
}
- return defaults;
+ return appendDoc(spec, defaults);
} else if (types.includes('array') && spec.hasOwnProperty('*')) {
return [generate(spec['*'], {})];
}
diff --git a/includes/helpers/cdn.js b/includes/helpers/cdn.js
index 9a7b9d8..8499e5f 100644
--- a/includes/helpers/cdn.js
+++ b/includes/helpers/cdn.js
@@ -49,6 +49,9 @@ module.exports = function (hexo) {
if (_package === 'pace-js') {
_package = 'pace';
}
+ if (_package === 'clipboard') {
+ _package = 'clipboard.js';
+ }
}
if (provider !== null && cdn_providers.hasOwnProperty(provider)) {
provider = cdn_providers[provider];
diff --git a/includes/helpers/site.js b/includes/helpers/site.js
index ef50a0d..7641295 100644
--- a/includes/helpers/site.js
+++ b/includes/helpers/site.js
@@ -3,13 +3,17 @@
*
* @example
* <%- is_same_link(url_a, url_b) %>
+* <%- get_domain(url) %>
* <%- post_count() %>
* <%- category_count() %>
* <%- tag_count() %>
* <%- duration() %>
* <%- word_count(content) %>
+* <%- md5(data) %>
*/
+const URL = require('url').URL;
const moment = require('moment');
+const crypto = require('crypto');
module.exports = function (hexo) {
hexo.extend.helper.register('is_same_link', function (a, b) {
@@ -23,6 +27,11 @@ module.exports = function (hexo) {
return santize(this.url_for(a)) == santize(this.url_for(b));
});
+ hexo.extend.helper.register('get_domain', function (link) {
+ const url = new URL(link);
+ return url.hostname;
+ });
+
hexo.extend.helper.register('post_count', function () {
return this.site.posts.length;
});
@@ -50,4 +59,8 @@ module.exports = function (hexo) {
content = content.trim();
return content ? (content.match(/[\u00ff-\uffff]|[a-zA-Z]+/g) || []).length : 0;
});
+
+ hexo.extend.helper.register('md5', function (data) {
+ return crypto.createHash('md5').update(data).digest("hex")
+ });
}
\ No newline at end of file
diff --git a/includes/specs/comment.spec.js b/includes/specs/comment.spec.js
index a169a18..c844ba6 100644
--- a/includes/specs/comment.spec.js
+++ b/includes/specs/comment.spec.js
@@ -24,30 +24,40 @@ const DisqusSpec = {
}
};
-const GitmentSpec = {
+const GitmentGitalkSpec = {
owner: {
[type]: 'string',
- [doc]: 'Your GitHub ID',
+ [doc]: 'GitHub user ID',
[required]: true,
- [requires]: comment => comment.type === 'gitment'
+ [requires]: comment => comment.type === 'gitment' || comment.type === 'gitalk'
},
repo: {
[type]: 'string',
- [doc]: 'The repo to store comments',
+ [doc]: 'GitHub repo name to store comments',
[required]: true,
- [requires]: comment => comment.type === 'gitment'
+ [requires]: comment => comment.type === 'gitment' || comment.type === 'gitalk'
},
client_id: {
[type]: 'string',
- [doc]: 'Your client ID',
+ [doc]: 'GitHub application client ID',
[required]: true,
- [requires]: comment => comment.type === 'gitment'
+ [requires]: comment => comment.type === 'gitment' || comment.type === 'gitalk'
},
client_secret: {
[type]: 'string',
- [doc]: 'Your client secret',
+ [doc]: 'GitHub application client secret',
[required]: true,
- [requires]: comment => comment.type === 'gitment'
+ [requires]: comment => comment.type === 'gitment' || comment.type === 'gitalk'
+ },
+ admin: {
+ [type]: ['string', 'array'],
+ [doc]: 'GitHub repo owner and collaborators who can can initialize github issues',
+ [required]: true,
+ [requires]: comment => comment.type === 'gitalk',
+ '*': {
+ [type]: 'string',
+ [required]: true
+ }
}
};
@@ -112,7 +122,7 @@ module.exports = {
},
...ChangYanSpec,
...DisqusSpec,
- ...GitmentSpec,
+ ...GitmentGitalkSpec,
...IssoSpec,
...LiveReSpec,
...ValineSpec
diff --git a/includes/specs/config.spec.js b/includes/specs/config.spec.js
index 8812794..57ce280 100644
--- a/includes/specs/config.spec.js
+++ b/includes/specs/config.spec.js
@@ -17,6 +17,7 @@ module.exports = {
article: require('./article.spec'),
search: require('./search.spec'),
comment: require('./comment.spec'),
+ donate: require('./donate.spec'),
share: require('./share.spec'),
sidebar: require('./sidebar.spec'),
widgets: require('./widgets.spec'),
diff --git a/includes/specs/donate.spec.js b/includes/specs/donate.spec.js
new file mode 100644
index 0000000..ed13e5f
--- /dev/null
+++ b/includes/specs/donate.spec.js
@@ -0,0 +1,72 @@
+const { doc, type, defaultValue, required, requires, format } = require('../common/utils').descriptors;
+
+const DEFAULT_DONATE = [
+ {
+ type: 'alipay',
+ qrcode: ''
+ },
+ {
+ type: 'wechat',
+ qrcode: ''
+ },
+ {
+ type: 'paypal',
+ business: '',
+ currency_code: 'USD'
+ },
+ {
+ type: 'patreon',
+ url: ''
+ }
+];
+
+const QrcodeSpec = {
+ qrcode: {
+ [type]: 'string',
+ [doc]: 'Qrcode image URL',
+ [required]: true,
+ [requires]: donate => donate.type === 'alipay' || donate.type === 'wechat'
+ }
+};
+
+const PaypalSpec = {
+ business: {
+ [type]: 'string',
+ [doc]: 'Paypal business ID or email address',
+ [required]: true,
+ [requires]: donate => donate.type === 'paypal'
+ },
+ currency_code: {
+ [type]: 'string',
+ [doc]: 'Currency code',
+ [required]: true,
+ [requires]: donate => donate.type === 'paypal'
+ }
+};
+
+const PatreonSpec = {
+ url: {
+ [type]: 'string',
+ [doc]: 'URL to the Patreon page',
+ [required]: true,
+ [requires]: donate => donate.type === 'patreon'
+ }
+};
+
+module.exports = {
+ [type]: 'array',
+ [doc]: 'Donation entries\nhttp://ppoffice.github.io/hexo-theme-icarus/categories/Donation/',
+ [defaultValue]: DEFAULT_DONATE,
+ '*': {
+ [type]: 'object',
+ [doc]: 'Single donation entry settings',
+ type: {
+ [type]: 'string',
+ [doc]: 'Donation entry name',
+ [required]: true
+ },
+ ...QrcodeSpec,
+ ...PaypalSpec,
+ ...PatreonSpec
+ }
+}
\ No newline at end of file
diff --git a/includes/specs/plugins.spec.js b/includes/specs/plugins.spec.js
index e912399..27b9b5a 100644
--- a/includes/specs/plugins.spec.js
+++ b/includes/specs/plugins.spec.js
@@ -59,5 +59,10 @@ module.exports = {
[type]: 'boolean',
[doc]: 'Show a loading progress bar at top of the page',
[defaultValue]: true
+ },
+ clipboard: {
+ [type]: 'boolean',
+ [doc]: 'Show the copy button in the highlighted code area',
+ [defaultValue]: true
}
};
\ No newline at end of file
diff --git a/languages/en.yml b/languages/en.yml
index 401bc45..816fe2c 100644
--- a/languages/en.yml
+++ b/languages/en.yml
@@ -25,6 +25,12 @@ article:
read: 'read'
about: 'About'
words: 'words'
+donate:
+ title: 'Like this article? Support the author with'
+ alipay: 'Alipay'
+ wechat: 'Wechat'
+ paypal: 'Paypal'
+ patreon: 'Patreon'
plugin:
backtotop: 'Back to Top'
search:
diff --git a/languages/id.yml b/languages/id.yml
index 52c8c54..ab3d036 100644
--- a/languages/id.yml
+++ b/languages/id.yml
@@ -6,32 +6,40 @@ common:
one: 'Kategori'
other: 'Kategori'
tag:
- one: 'tag'
- other: 'tag'
+ one: 'Tag'
+ other: 'Tag'
post:
- one: 'pos'
- other: 'pos'
+ one: 'Artikel'
+ other: 'Artikel'
prev: 'Sebelumnya'
next: 'Berikutnya'
widget:
follow: 'IKUTI'
recents: 'Terbaru'
- links: 'tautan'
- tag_cloud: 'awan tag'
- catalogue: 'Catalogue'
+ links: 'Tautan'
+ tag_cloud: 'Awan tag'
+ catalogue: 'Katalog'
article:
- more: 'Read More'
+ more: 'Selengkapnya'
comments: 'Komentar'
- read: 'read'
- about: 'About'
- words: 'words'
+ read: 'membaca'
+ about: 'Sekitar'
+ words: 'kata'
search:
- search: 'Search'
+ search: 'Pencarian'
hint: 'Tulis Sesuatu..'
insight:
hint: 'Tulis Sesuatu..'
- posts: 'Pos'
+ posts: 'Artikel'
pages: 'Halaman'
categories: 'Kategori'
tags: 'Tag'
untitled: 'Tanpa Judul'
+donate:
+ title: 'Suka dengan artikel ini? Bantu penulis dengan donasi melalui'
+ alipay: 'Alipay'
+ wechat: 'Wechat'
+ paypal: 'Paypal'
+ patreon: 'Patreon'
+plugin:
+ backtotop: 'Kembali ke atas'
diff --git a/languages/zh-CN.yml b/languages/zh-CN.yml
index 99ec4f5..5ca1fc7 100644
--- a/languages/zh-CN.yml
+++ b/languages/zh-CN.yml
@@ -25,6 +25,10 @@ article:
read: '读完'
about: '大约'
words: '个字'
+donate:
+ title: '喜欢这篇文章?打赏一下作者吧'
+ alipay: '支付宝'
+ wechat: '微信'
plugin:
backtotop: '回到顶端'
search:
diff --git a/languages/zh-TW.yml b/languages/zh-TW.yml
index 6791f2a..bacc55e 100644
--- a/languages/zh-TW.yml
+++ b/languages/zh-TW.yml
@@ -1,7 +1,7 @@
common:
archive:
- one: '歸檔'
- other: '歸檔'
+ one: '彙整'
+ other: '彙整'
category:
one: '分類'
other: '分類'
@@ -14,7 +14,7 @@ common:
prev: '上一頁'
next: '下一頁'
widget:
- follow: '關注我'
+ follow: '追蹤'
recents: '最新文章'
links: '連結'
tag_cloud: '標籤雲'
@@ -22,16 +22,24 @@ widget:
article:
more: '繼續閱讀'
comments: '評論'
- read: 'read'
- about: 'About'
- words: 'words'
+ read: '閱讀文'
+ about: '大約'
+ words: '個字'
+donate:
+ title: '喜歡這篇文章嗎? 贊助一下作者吧!'
+ alipay: '支付寶'
+ wechat: 'WeChat'
+ paypal: 'PayPal'
+ patreon: 'Patreon'
+plugin:
+ backtotop: '回到頁首'
search:
- search: '搜索'
- hint: 'Type something...'
+ search: '搜尋'
+ hint: '請輸入關鍵字...'
insight:
- hint: 'Type something...'
+ hint: '請輸入關鍵字...'
posts: '文章'
- pages: 'Pages'
+ pages: '頁面'
categories: '分類'
tags: '標籤'
- untitled: '(Untitled)'
+ untitled: '(無標題)'
diff --git a/layout/comment/gitalk.ejs b/layout/comment/gitalk.ejs
new file mode 100644
index 0000000..e49aae9
--- /dev/null
+++ b/layout/comment/gitalk.ejs
@@ -0,0 +1,22 @@
+<% if (!has_config('comment.owner') || !has_config('comment.admin') || !has_config('comment.repo') || !has_config('comment.client_id') ||
+ !has_config('comment.client_secret')) { %>
+
+ You forgot to set the owner
, admin
, repo
, client_id
, or client_secret
for Gittalk.
+ Please set it in _config.yml
.
+
+<% } else { %>
+
+<%- _css(cdn('gitalk', '1.4.1', 'dist/gitalk.css')) %>
+<%- _js(cdn('gitalk', '1.4.1', 'dist/gitalk.min.js')) %>
+
+<% } %>
\ No newline at end of file
diff --git a/layout/common/article.ejs b/layout/common/article.ejs
index fe97d17..d3149f2 100644
--- a/layout/common/article.ejs
+++ b/layout/common/article.ejs
@@ -70,6 +70,23 @@
+<% const services = has_config('donate') ? get_config('donate') : []; %>
+<% if (!index && services.length > 0) { %>
+
diff --git a/layout/donate/alipay.ejs b/layout/donate/alipay.ejs
new file mode 100644
index 0000000..5ced298
--- /dev/null
+++ b/layout/donate/alipay.ejs
@@ -0,0 +1,14 @@
+<% const qrcode = get_config_from_obj(service, 'qrcode');
+ if (qrcode) { %>
+
+
+
+
+ <%= __('donate.' + type) %>
+
+
+<% } else { %>
+
+ You forgot to set the qrcode
for Alipay. Please set it in _config.yml
.
+
+<% } %>
\ No newline at end of file
diff --git a/layout/donate/patreon.ejs b/layout/donate/patreon.ejs
new file mode 100644
index 0000000..16de91a
--- /dev/null
+++ b/layout/donate/patreon.ejs
@@ -0,0 +1,13 @@
+<% const url = get_config_from_obj(service, 'url');
+ if (url) { %>
+
+
+
+
+ <%= __('donate.' + type) %>
+
+<% } else { %>
+
+ You forgot to set the url
Patreon. Please set it in _config.yml
.
+
+<% } %>
\ No newline at end of file
diff --git a/layout/donate/paypal.ejs b/layout/donate/paypal.ejs
new file mode 100644
index 0000000..f4cb854
--- /dev/null
+++ b/layout/donate/paypal.ejs
@@ -0,0 +1,20 @@
+
+<% const business = get_config_from_obj(service, 'business');
+ const currency_code = get_config_from_obj(service, 'currency_code');
+ if (business && currency_code) { %>
+
+
+
+
+ <%= __('donate.' + type) %>
+
+
+<% } else { %>
+
+ You forgot to set the business
and currency_code
for Paypal. Please set it in _config.yml
.
+
+<% } %>
\ No newline at end of file
diff --git a/layout/donate/wechat.ejs b/layout/donate/wechat.ejs
new file mode 100644
index 0000000..a1a6faa
--- /dev/null
+++ b/layout/donate/wechat.ejs
@@ -0,0 +1,14 @@
+<% const qrcode = get_config_from_obj(service, 'qrcode');
+ if (qrcode) { %>
+
+
+
+
+ <%= __('donate.' + type) %>
+
+
+<% } else { %>
+
+ You forgot to set the qrcode
for Wechat. Please set it in _config.yml
.
+
+<% } %>
\ No newline at end of file
diff --git a/layout/plugin/clipboard.ejs b/layout/plugin/clipboard.ejs
new file mode 100644
index 0000000..dc764e4
--- /dev/null
+++ b/layout/plugin/clipboard.ejs
@@ -0,0 +1,6 @@
+<% if (plugin !== false) { %>
+ <% if (!head) { %>
+ <%- _js(cdn('clipboard', '2.0.4', 'dist/clipboard.min.js'), true) %>
+ <%- _js('js/clipboard', true) %>
+ <% } %>
+<% } %>
\ No newline at end of file
diff --git a/layout/widget/links.ejs b/layout/widget/links.ejs
index c87c605..2a1e629 100644
--- a/layout/widget/links.ejs
+++ b/layout/widget/links.ejs
@@ -14,7 +14,7 @@
<%= i %>
- <%- links[i] %>
+ <%- get_domain(links[i]) %>
diff --git a/package.json b/package.json
index 183c998..da63e1a 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
"name": "hexo-theme-icarus",
- "version": "2.0.0",
+ "version": "2.3.0",
"private": true
}
diff --git a/source/css/style.styl b/source/css/style.styl
index ef01c5f..a7a57bb 100644
--- a/source/css/style.styl
+++ b/source/css/style.styl
@@ -50,16 +50,18 @@ body, button, input, select, textarea
top: 1.5rem
.card
- overflow: hidden
border-radius: 4px
box-shadow: 0 4px 10px rgba(0,0,0,0.05), 0 0 1px rgba(0,0,0,0.1)
& + .card,
& + .column-right-shadow
margin-top: 1.5rem
&.card-transparent
- overflow: visible
box-shadow: none
background: transparent
+ .card-image
+ overflow: hidden
+ border-top-left-radius: 4px
+ border-top-right-radius: 4px
img.thumbnail
object-fit: cover
@@ -181,6 +183,30 @@ img.thumbnail
margin-left: 0.75rem
margin-right: 0
+.donate
+ position: relative
+ .qrcode
+ display: none
+ position: absolute
+ z-index: 99
+ bottom: 2.5em
+ line-height: 0
+ overflow: hidden
+ border-radius: 4px
+ box-shadow: 0 4px 10px rgba(0,0,0,.1), 0 0 1px rgba(0,0,0,.2)
+ overflow: hidden
+ img
+ max-width: 280px
+ &:hover
+ .qrcode
+ display: block
+ &:first-child:not(:last-child)
+ .qrcode
+ left: -0.75rem
+ &:last-child:not(:first-child)
+ .qrcode
+ right: -0.75rem
+
@media screen and (max-width: screen-tablet - 1)
#toc
display: none
@@ -210,6 +236,9 @@ img.thumbnail
/* ---------------------------------
* Custom modifiers
* --------------------------------- */
+.is-borderless
+ border: none
+
.is-size-7
font-size: 0.85rem !important
@@ -318,6 +347,7 @@ img.thumbnail
figure.highlight
padding: 0
width: 100%
+ position: relative
margin: 1em 0 1em !important
pre,
@@ -371,6 +401,16 @@ figure.highlight
min-width: inherit
border-radius: inherit
+ .copy
+ display: none
+ position: absolute
+ bottom: 0
+ right: 0
+ color: white
+ background: rgba(0, 0, 0, 0.5)
+ &:hover .copy
+ display: block
+
/* ---------------------------------
* Fix Gist Snippet
* --------------------------------- */
diff --git a/source/js/clipboard.js b/source/js/clipboard.js
new file mode 100644
index 0000000..2e0e4d4
--- /dev/null
+++ b/source/js/clipboard.js
@@ -0,0 +1,10 @@
+document.addEventListener('DOMContentLoaded', function () {
+ if (typeof(ClipboardJS) !== 'undefined') {
+ $('figure.highlight').each(function () {
+ var id = 'code-' + Date.now() + (Math.random() * 1000 | 0);
+ $(this).attr('id', id);
+ $(this).prepend($(`
`));
+ });
+ new ClipboardJS('.highlight .copy');
+ }
+});
\ No newline at end of file