icarus个性化配置

本博客所选取的主题是 Icarus ,并做了一些个性化的修改,很多修改都可以直观的看到。

布局

文章页面两栏布局

主题默认是双栏布局,在阅读文章时显得有些拥挤。可以通过配置的方式把所有文章变为两栏布局,在_config.post.yml把需要的widget显示在一边即可,可以参考官方文档

但两栏整体宽度跟三栏不同,因此强制指定为三栏布局,并且修改相应的宽度,这样所有的页面侧边栏宽度保持一致。

layout/layout.jsx
1
2
3
4
             <Head site={site} config={config} helper={helper} page={page} />
- <body class={`is-${columnCount}-column`}>
+ <body class={`is-3-column`}>
<Navbar config={config} helper={helper} page={page} />
layout/layout.jsx
1
2
3
4
                                 'is-12': columnCount === 1,
- 'is-8-tablet is-8-desktop is-8-widescreen': columnCount === 2,
+ 'is-8-tablet is-8-desktop is-9-widescreen': columnCount === 2,
'is-8-tablet is-8-desktop is-6-widescreen': columnCount === 3
layout/common/widgets.jsx
1
2
3
4
5
6
7
8
 function getColumnSizeClass(columnCount) {
switch (columnCount) {
case 2:
- return 'is-4-tablet is-4-desktop is-4-widescreen';
+ return 'is-4-tablet is-4-desktop is-3-widescreen';
case 3:
return 'is-4-tablet is-4-desktop is-3-widescreen';
}

并优化在不同屏幕小大下的宽度

include/style/responsive.styl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 +widescreen()
+ .is-3-column .container
+ max-width: $widescreen - $gap
+ width: $widescreen - $gap
+
.is-1-column .container, .is-2-column .container
max-width: $desktop - 2 * $gap
width: $desktop - 2 * $gap

+fullhd()
+ .is-3-column .container
+ max-width: $fullhd - 2 * $gap
+ width: $fullhd - 2 * $gap
+
.is-2-column .container
max-width: $widescreen - 2 * $gap
width: $widescreen - 2 * $gap

优化文章标题布局

标题移动到文章信息上方,增加更新时间,并增加了icon

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
diff: layout/common/article.jsx
<article class={`card-content article${'direction' in page ? ' ' + page.direction : ''}`} role="article">
{/* Metadata */}
+ {/* 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)}>
+ <i className="fas fa-angle-double-right"></i>{page.title}
+ </a> :
+ [<i className="fas fa-angle-double-right"></i>, page.title]
+ }
+ </h1>
{page.layout !== 'page' ? <div class="article-meta is-size-7 is-uppercase level is-mobile">
<div class="level-left">
{/* Creation Date */}
- {page.date && <span class="level-item" dangerouslySetInnerHTML={{
- __html: _p('article.created_at', `<time dateTime="${date_xml(page.date)}" title="${new Date(page.date).toLocaleString()}">${date(
page.date)}</time>`)
- }}></span>}
+ {page.date && <span class="level-item">
+ <i className="far fa-calendar-alt">&nbsp;</i>
+ <time dateTime={date_xml(page.date)} title={date_xml(page.date)}>{date(page.date)}</time>
+ </span>}
{/* Last Update Date */}
- {page.updated && <span class="level-item" dangerouslySetInnerHTML={{
- __html: _p('article.updated_at', `<time dateTime="${date_xml(page.updated)}" title="${new Date(page.updated).toLocaleString()}">$
{date(page.updated)}</time>`)
- }}></span>}
+ {shouldShowUpdated && <span class="level-item is-hidden-mobile">
+ <i class="far fa-calendar-check">&nbsp;</i>
+ <time dateTime={date_xml(page.updated)} title={date_xml(page.updated)}>{date(page.updated)}</time>
+ </span>}
{/* author */}
{page.author ? <span class="level-item"> {page.author} </span> : null}

其中时间直接使用日期

source/js/main.js
1
2
3
4
5
-    if (typeof moment === 'function') {
- $('.article-meta time').each(function() {
- $(this).text(moment($(this).attr('datetime')).fromNow());
- });
- }

优化文章结尾布局

在文章结尾增加一个 hr,并修改 tags 展示。在预览时(主页)也显示 tags,并且将 Read More 按钮放置在右边。

layout/common/article.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
                     {/* Licensing block */}
{!index && article && article.licenses && Object.keys(article.licenses)
? <ArticleLicensing.Cacheable page={page} config={config} helper={helper} /> : null}
+ <hr style="height:1px;margin:1rem 0"/>
+ <div className="level is-mobile is-flex">
{/* Tags */}
- {!index && page.tags && page.tags.length ? <div class="article-tags is-size-7 mb-4">
- <span class="mr-2">#</span>
- {page.tags.map(tag => {
- return <a class="link-muted mr-2" rel="tag" href={url_for(tag.path)}>{tag.name}</a>;
+ {page.tags && page.tags.length ? <div class="article-tags is-size-7 is-uppercase">
+ <i class="fas fa-tags has-text-grey"></i>&nbsp;
+ {page.tags.map((tag, index) => {
+ return <a class="link-muted" rel="tag" href={url_for(tag.path)}>{tag.name}{index !== page.tags.length-1? ', ':''}</a>;
})}
</div> : null}
{/* "Read more" button */}
- {index && page.excerpt ? <a class="article-more button is-small is-size-7" href={`${url_for(page.link || page.path)}#more`}>{__('article.more')}</a> : null}
+ {index && page.excerpt ? <a class="article-more button is-small is-size-7" href={`${url_for(page.link || page.path)}#more`}><i class="fas fa-book-reader has-text-grey"></i>&nbsp;&nbsp;{__('article.more')}</a> : null}
+ </div>
{/* Share button */}

优化个人信息布局

减少头像大小,头像下方计数的地方增加链接,follow前增加icon。

1
2
3
4
5
6
7
8
9
10
11
12
13
diff: layout/widget/profile.jsx
- <div class="level-item has-text-centered is-marginless">
+ <a class="level-item has-text-centered is-marginless" href={counter.category.url}>
<div>
<p class="heading">{counter.category.title}</p>
- <a href={counter.category.url}>
+ <div>
<p class="title">{counter.category.count}</p>
- </a>
+ </div>
</div>
- </div>
+ </a>

优化移动端显示

在移动端,隐藏 archive 和 tags。

source/js/main.js
1
2
3
4
5
     }
+
+ $('div.container div.card[data-type=tags]').addClass('is-hidden-mobile');
+ $('div.container div.card[data-type=archives]').addClass('is-hidden-mobile');
}(jQuery, window.moment, window.ClipboardJS, window.IcarusThemeSettings));

目录粘性定位

原来只支持侧边栏整体粘性定位,为了阅读体验,只针对目录开启粘性定位,增加 column-left is-sticky 类,并调整样式

source/js/main.js
1
2
3
     if ($toc.length > 0) {
+ $toc.addClass('column-left is-sticky');
const $mask = $('<div>');
include/style/widget.styl
1
2
3
+#toc
+ max-height: calc(100vh - 22px)
+ overflow-y: scroll

功能

增加默认缩略图

1
2
3
4
5
6
diff: layout/layout.jsx
const { site, config, page, helper, body } = this.props;

+ site.posts && site.posts.filter(p => !p.thumbnail).forEach(p => p.thumbnail = '/img/thumbnail.svg');
+
const language = page.lang || page.language || config.language;
layout/archive.jsx
1
2
3
4
5
         const { url_for, __, date_xml, date } = helper;

+ page.posts && page.posts.filter(p => !p.thumbnail).forEach(p => p.thumbnail = '/img/thumbnail.svg');
+
const language = page.lang || page.language || config.language;

增加许可协议

新版已经支持许可协议,直接配置即可,参考官方文档

增加标题自动计数

1
2
3
4
5
6
7
8
diff: include/style/article.styl
+.article {counter-reset:section}
+.article h2{counter-reset:sub-section}
+.article h3{counter-reset:composite}
+.article h4{counter-reset:detail}
+.article h2:before{content:counter(section) " ";counter-increment:section}
+.article h3:before{content:counter(section) "." counter(sub-section) " ";counter-increment:sub-section}
+.article h4:before{content:counter(section) "." counter(sub-section) "." counter(composite) " ";counter-increment:composite}

默认显示目录

新版支持直接配置,在_config.yml增加toc: true即可。

页面footer显示一组icon

默认情况下一个icon对应一个链接,但例如 CC BY-NC-SA 4.0 需要四个图标一组。因此修改代码,使得配置 link.icon 可以是一个数组,效果可以参考页面底部。

layout/common/footer.jsx
1
2
3
4
5
6
7
8
9
10
11
12
                                 const link = links[name];
return <p class="control">
<a class={`button is-transparent ${link.icon ? 'is-large' : ''}`} target="_blank" rel="noopener" title={name} href={link.url}>
- {link.icon ? <i class={link.icon}></i> : name}
+ {link.icon ?
+ (Array.isArray(link.icon) ?
+ link.icon.map(i => [<i className={i}></i>, '\u00A0']) :
+ <i className={link.icon}></i>
+ ) : name}
</a>
</p>;
})}

忽略校验的schema

include/schema/common/footer.json
1
-            "$ref": "/misc/poly_links.json",

_config.yml 中配置如下

_config.yml
1
2
3
4
5
6
7
8
9
footer:
links:
CC BY-NC-SA 4.0:
icon:
- fab fa-creative-commons
- fab fa-creative-commons-by
- fab fa-creative-commons-nc
- fab fa-creative-commons-sa
url: 'https://creativecommons.org/licenses/by-nc-sa/4.0/'

添加评论系统

参考valine官方的快速开始文档,创建LeanCloud应用,修改_config.icarus.ymlcomment的配置项,填入对应的app_idapp_key即可

_config.icarus.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
comment:
type: valine
app_id: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
app_key: xxxxxxxxxxxxxxxxxxxxxx
placeholder: "" # 可选填
avatar: mm # 可选填
avatar_force: false # 可选填
meta: ["nick", "mail", "link"] # 可选填
page_size: 10 # 可选填
lang: zh-CN # 可选填
visitor: false # 可选填
highlight: true # 可选填
record_ip: false # 可选填
server_urls: # 可选填
emoji_cdn: # 可选填
emoji_maps: # 可选填
enable_qq: false # 可选填
required_fields: [] # 可选填

给文章添加分享功能

直接在_config.icarus.yml中修改插件为sharejs即可

_config.icarus.yml
1
2
3
4
5
6
# Share plugin configurations
# https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Share/
share:
type: sharejs
# URL to the ShareThis share plugin script
# install_url: ''

为博客添加nest动态线条特效

themes\icarus\layout\layout.jsxbody中添加如下代码,CDN可根据自己使用的修改

themes\icarus\layout\layout.jsx
1
<script type="text/javascript" color="30,144,255" opacity='0.5' zIndex="-1" count="150" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"></script>

除了通过CDN加载,也可以下载到本地使用,详见官方文档

页脚添加网站运行时间

网上找到的都是ejs的写法,其实jsx的写法也很简单,只要把js的代码嵌入jsx中就可以了。在themes\icarus\layout\common\head.jsx中找到要添加运行时间的位置,比如在不蒜子前面添加,代码如下

themes\icarus\layout\common\head.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<p class="is-size-7">
<span dangerouslySetInnerHTML={{ __html: `&copy; ${siteYear} ${author || siteTitle}` }}></span>
&nbsp;&nbsp;Powered by <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>&nbsp;&&nbsp;
<a href="https://github.com/ppoffice/hexo-theme-icarus" target="_blank" rel="noopener">Icarus</a>
<br />
+ <span id="timeDate">载入天数...</span><span id="times">载入时分秒...</span>
+ <script dangerouslySetInnerHTML={{
+ __html: `
+ var now = new Date();
+ function createtime() {
+ var grt= new Date("2/27/2020 16:23:00");//此处修改你的建站时间或者网站上线时间
+ now.setTime(now.getTime()+250);
+ days = (now - grt ) / 1000 / 60 / 60 / 24; dnum = Math.floor(days);
+ hours = (now - grt ) / 1000 / 60 / 60 - (24 * dnum); hnum = Math.floor(hours);
+ if(String(hnum).length ==1 ){hnum = "0" + hnum;} minutes = (now - grt ) / 1000 /60 - (24 * 60 * dnum) - (60 * hnum);
+ mnum = Math.floor(minutes); if(String(mnum).length ==1 ){mnum = "0" + mnum;}
+ seconds = (now - grt ) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
+ snum = Math.round(seconds); if(String(snum).length ==1 ){snum = "0" + snum;}
+ document.getElementById("timeDate").innerHTML = "| 本站已运行 "+dnum+" 天 ";
+ document.getElementById("times").innerHTML = hnum + " 小时 " + mnum + " 分 " + snum + " 秒";
+ }
+ setInterval("createtime()",250);
+ `,
+ }}
+ />
{showVisitorCounter ? <br /> : null}
{showVisitorCounter ? <span id="busuanzi_container_site_uv"
dangerouslySetInnerHTML={{ __html: visitorCounterTitle }}></span> : null}
</p>

修改页脚不蒜子,增加总访问量统计

render()中添加变量visitCountTitle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
render() {
const {
logo,
logoUrl,
siteUrl,
siteTitle,
siteYear,
author,
links,
showVisitorCounter,
visitorCounterTitle,
+ visitCounterTitle
} = this.props;
……
……
}

在原来不蒜子的位置新增总访问量统计的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<p class="is-size-7">
<span dangerouslySetInnerHTML={{ __html: `&copy; ${siteYear} ${author || siteTitle}` }}></span>
&nbsp;&nbsp;Powered by <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>&nbsp;&&nbsp;
<a href="https://github.com/ppoffice/hexo-theme-icarus" target="_blank" rel="noopener">Icarus</a>
<br />
<span id="timeDate">载入天数...</span><span id="times">载入时分秒...</span>
<script dangerouslySetInnerHTML={{
__html: `
var now = new Date();
function createtime() {
var grt= new Date("2/27/2020 16:23:00");//此处修改你的建站时间或者网站上线时间
now.setTime(now.getTime()+250);
days = (now - grt ) / 1000 / 60 / 60 / 24; dnum = Math.floor(days);
hours = (now - grt ) / 1000 / 60 / 60 - (24 * dnum); hnum = Math.floor(hours);
if(String(hnum).length ==1 ){hnum = "0" + hnum;} minutes = (now - grt ) / 1000 /60 - (24 * 60 * dnum) - (60 * hnum);
mnum = Math.floor(minutes); if(String(mnum).length ==1 ){mnum = "0" + mnum;}
seconds = (now - grt ) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
snum = Math.round(seconds); if(String(snum).length ==1 ){snum = "0" + snum;}
document.getElementById("timeDate").innerHTML = "| 本站已运行 "+dnum+" 天 ";
document.getElementById("times").innerHTML = hnum + " 小时 " + mnum + " 分 " + snum + " 秒";
}
setInterval("createtime()",250);
`,
}}
/>
{showVisitorCounter ? <br /> : null}
{showVisitorCounter ? <span id="busuanzi_container_site_uv"
dangerouslySetInnerHTML={{ __html: visitorCounterTitle }}></span> : null}
+ {showVisitorCounter ? <span> | </span> : null}
+ {showVisitorCounter ? <span id="busuanzi_container_site_pv"
+ dangerouslySetInnerHTML={{ __html: visitCounterTitle }}></span> : null}
</p>

module.exports中添加visitCounterTitle的返回值

1
2
3
4
5
6
7
8
9
10
11
12
return {
logo,
logoUrl: url_for(logo),
siteUrl: url_for('/'),
siteTitle: title,
siteYear: date(new Date(), 'YYYY'),
author,
links,
showVisitorCounter: plugins && plugins.busuanzi === true,
visitorCounterTitle: _p('plugin.visitor_count', '<span id="busuanzi_value_site_uv">0</span>'),
+ visitCounterTitle: _p('plugin.visit_count_total', '<span id="busuanzi_value_site_pv">0</span>')
};

在\themes\icarus\languages\zh-CN.yml中的plugin添加visit_count_total字段

\themes\icarus\languages\zh-CN.yml
1
2
3
4
5
plugin:
backtotop: '回到顶端'
visit_count: '%s次访问'
visitor_count: '共%s个访客'
+ visit_count_total: '总访问量%s'

样式

修改 logo 和 favicon

用 Python 设计 Logo,并微调样式。

按钮背景颜色增加渐变

include/style/widget.styl
1
2
3
4
5
6
7
8
9
 .widget
.menu-list
li
ul
margin-right: 0
+ a
+ transition: background-color 0.3s ease-in-out
.level
margin-bottom: 0

card 增加浮动效果

:hover 时增大阴影,并增加动画属性 ease-in-out

include/style/card.styl
1
2
3
4
5
 .card
overflow: visible
border-radius: $card-radius
+ &:hover
+ box-shadow: 0 6px 15px rgba(0,0,0,0.15), 0 0 1px rgba(0,0,0,0.1)
source/js/animation.js
1
2
3
4
5
6
     setTimeout(() => {
$('body > .navbar, body > .section, body > .footer').forEach(element => {
element.style.opacity = '1';
- element.style.transition = 'opacity 0.3s ease-out, transform 0.3s ease-out';
+ element.style.transition = 'opacity 0.3s ease-out, transform 0.3s ease-out, box-shadow 0.3s ease-in-out';
});
source/js/animation.js
1
2
3
4
                     element.style.transform = '';
- element.style.transition = 'opacity 0.3s ease-out, transform 0.3s ease-out';
+ element.style.transition = 'opacity 0.3s ease-out, transform 0.3s ease-out, box-shadow 0.3s ease-in-out';
}, i * 100);

修改tag的颜色

include/style/widget.styl
1
2
3
4
5
6
7
8
9
10
11
     .tags
.tag:first-child
- background: $primary
- color: $primary-invert
+ background: whitesmoke
+ color: #4a4a4a

.tag:last-child
- background: $light-grey
+ background: #e7e7e7
color: $white-invert

更新

2020-12-04 基于 4.1.1 版本重新改动。
2021-09-06 合并 4.4.0,官方也支持文章 licenses配置多个图标,不过目前还是自己实现的。

总结

这里只列举了部分改动,详细的差异可以查看 diff

本文会持续更新,保持跟最新的博客效果一致,希望能给你自定义主题一些帮助。

如果有其他想法或者意见,可以在下方留言。