博客更换ICARUS主题

前言

最近无意间留意到一个比较符合我口味的主题,也许是因为Next主题被我看腻了,于是就换了icarus然后接下来当然是各种折腾,总算是告一段落可以安心的做别的事情了。

主题介绍

主题地址:https://github.com/ppoffice/hexo-theme-icarus

这个主题可以完全替代Next主题,比较让我喜欢的是简洁大气的界面风格,另外还有细致的侧边栏以及订制功能,总结一下特点如下:

  1. 整体的界面美观大方。
  2. Icarus包含常用的搜索,评论,分享和其他插件。
  3. 可设置文章头图片。
  4. 超过70种highlight.js样式可选。
  5. 可以自定义侧边栏。
  6. 字体风格漂亮。
  7. 可在文章内自定义菜单。
  8. 响应式布局。

主题配置

导航栏

和Next不同的是不要配置font图标,只需要配置路径即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
navbar:
# Navigation bar menu links
menu:
首页: /
归档: /archives/
资料: /keep/
友链: /links/
统计: /laboratory
相册: /photos/
关于: /about/
索引: /sitemap.xml
links:
Download on GitHub:
icon: fab fa-github
url: 'https://github.com/lxqxsyu'

页脚导航

我们可以在页脚的右下角设置链接导航。

1
2
3
4
5
6
7
8
9
10
11
12
footer:
# Links to be shown on the right of the footer section
links:
Creative Commons:
icon: fab fa-creative-commons
url: 'https://creativecommons.org/'
Attribution 4.0 International:
icon: fab fa-creative-commons-by
url: 'https://creativecommons.org/licenses/by/4.0/'
Download on GitHub:
icon: fab fa-github
url: 'https://github.com/lxqxsyu'

图库

还记得之前在Next中要搞一个相册有多麻烦,这个主题已经默认支持瀑布流的相册布局,你可以添加到文章的任意位置。

首先在_config.yml中开启画廊功能:

1
2
plugins:
gallery: true

添加画廊图片:

1
2
3
4
5
6
7
8
9
<div class="justified-gallery">
![Elephant](/hexo-theme-icarus/gallery/animals/elephant.jpeg)
![Dog](/hexo-theme-icarus/gallery/animals/dog.jpeg)
![Birds](/hexo-theme-icarus/gallery/animals/birds.jpeg)
![Cat](/hexo-theme-icarus/gallery/animals/cat.jpeg)
![Fox](/hexo-theme-icarus/gallery/animals/fox.jpeg)
![Horse](/hexo-theme-icarus/gallery/animals/horse.jpeg)
![Leopard](/hexo-theme-icarus/gallery/animals/leopard.jpeg)
</div>

设置侧边栏

侧边栏可以在widgets中设置,按照先后顺序显示,每个侧栏都可以设置左侧还是右侧显示,当然也可以隐藏。

修改主题

主题使用ejs和sass框架编写,结构清晰,甚至你都不需要会css都可以修改样式。

双栏模式

首页有左右侧边栏,其他页面只有左边侧边栏,这样可以在阅读文章的时候更舒服。

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
35
36
37
38
39
40
41
diff --git a/includes/helpers/layout.js b/includes/helpers/layout.js
index 7fd6c07..6bfd0b3 100644
--- a/includes/helpers/layout.js
+++ b/includes/helpers/layout.js
@@ -32,6 +32,9 @@ module.exports = function (hexo) {

hexo.extend.helper.register('column_count', function () {
let columns = 1;
+ if (this.page.__post === true || this.page.__page === true) {
+ return 2;
+ }
const hasColumn = hexo.extend.helper.get('has_column').bind(this);
columns += hasColumn('left') ? 1 : 0;
columns += hasColumn('right') ? 1 : 0;
diff --git a/layout/common/widget.ejs b/layout/common/widget.ejs
index 9f58bd5..c6b267c 100644
--- a/layout/common/widget.ejs
+++ b/layout/common/widget.ejs
@@ -25,7 +25,7 @@
<%- partial('widget/' + widget.type, { widget, post: page }) %>
<% }) %>
<% if (position === 'left') { %>
- <div class="column-right-shadow is-hidden-widescreen <%= sticky_class('right') %>">
+ <div class="column-right-shadow <%= (page.__page !== true && page.__post !== true) ? 'is-hidden-widescreen' : '' %> <%= sticky_class('right') %>">
<% get_widgets('right').forEach(widget => {%>
<%- partial('widget/' + widget.type, { widget, post: page }) %>
<% }) %>
diff --git a/layout/layout.ejs b/layout/layout.ejs
index cf7be87..b76c9e6 100644
--- a/layout/layout.ejs
+++ b/layout/layout.ejs
@@ -21,7 +21,9 @@
<div class="columns">
<div class="column <%= main_column_class() %> has-order-2 column-main"><%- body %></div>
<%- partial('common/widget', { position: 'left' }) %>
+ <% if (page.__page !== true && page.__post !== true) { %>
<%- partial('common/widget', { position: 'right' }) %>
+ <% } %>
</div>
</div>
</section>

文章区域放宽

这个文章内容区域是12格布局,可以修改source/css/style.styl文件中的@media screen样式如下:

1
2
3
4
5
6
7
8
9
10
11
12
@media screen and (min-width: screen-widescreen)
.is-1-column .container
.is-2-column .container
max-width: screen-widescreen - 2 * gap
width: screen-widescreen - 2 * gap
@media screen and (min-width: screen-fullhd)
.is-2-column .container
max-width: screen-fullhd - 2 * gap
width: screen-fullhd - 2 * gap
.is-1-column .container
max-width: screen-desktop - 2 * gap
width: screen-desktop - 2 * gap

再修改layout/layout.ejslayout/common/widget.ejs的文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
<% function main_column_class() {
switch (column_count()) {
case 1:
return 'is-12';
case 2:
return 'is-8-tablet is-9-desktop is-9-widescreen';
case 3:
return 'is-8-tablet is-8-desktop is-6-widescreen'
}
return '';
} %>

1
2
3
4
5
6
7
8
9
<% function side_column_class() {
switch (column_count()) {
case 2:
return 'is-4-tablet is-3-desktop is-3-widescreen';
case 3:
return 'is-4-tablet is-4-desktop is-3-widescreen';
}
return '';
} %>

要注意的是对应column的数量和是12,如果是三列就是三列的和,如果是两列就是两列的和。

添加51LA统计

这个统计有一大特点就是可以拥有一个有关网站的整体数据当月当日数据的挂件,还可以分析SEO,浏览者的IP,爬虫分析等。

_config.ymlbusuanzi: false代码下发添加配置:

1
2
3
plugins:
#51.la统计
tj51la: true

打开layout/common/footer.ejs文件的<span id="busuanzi_container_site_uv">下方添加如下代码:

1
2
3
<% if (has_config('plugins.tj51la') ? get_config('plugins.tj51la') : false) { %>

<% } %>

layout/plugin目录新建文件tj51la.ejs注意将xxxxxx修改为你自己的id.

1
2
3
4
5
<% if (plugin !== false) { %>
<% if (head) { %>
<script type="text/javascript" src="https://js.users.51.la/xxxxxx.js"></script>
<% } %>
<% } %>

如果需要你还可以在layout/common/footer.ejs中添加备案号等内容。

动态隐藏组件

上面提到过如何在page和post页面显示两栏,在首页显示三栏,我们可以判断当前的columns(几栏)来做不同的逻辑操作,有两种方法实现在两栏的时候隐藏部分侧边组件。

方法一:例如想取掉 tagclound widget,在 tagcloud.ejs 中添加判断是否是page或者post

1
2
3
4
5
6
7
8
9
10
11
12
+ <% if (page.__page !== true && page.__post !== true) { %>
<% if (site.tags.length) { %>
<div class="card widget">
<div class="card-content">
<h3 class="menu-label">
<%= __('widget.tag_cloud') %>
</h3>
<%- tagcloud() %>
</div>
</div>
<% } %>
+ <% } %>

方法二:在 layout/common/widget.ejs 中判断如果widget是不是tag组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="column <%= side_column_class() %> <%= visibility_class() %> <%= order_class() %> column-<%= position %> <%= sticky_class(position) %>">
<% get_widgets(position, column_count()).forEach(widget => {%>
<%- partial('widget/' + widget.type, { widget, post: page }) %>
<% }) %>
<% if (position === 'left') { %>
<div class="column-right-shadow <%= (page.__page !== true && page.__post !== true) ? 'is-hidden-widescreen' : '' %> <%= sticky_class('right') %>">
- <% get_widgets('right', column_count()).forEach(widget => {%>
+ <% get_widgets(right, column_count()).forEach(widget => { if(widget.type !== 'tag'){%>
<%- partial('widget/' + widget.type, { widget, post: page }) %>
- <% }) %>
+ <% }}) %>
</div>
<% } %>
</div>

修改组件的方向和位置

比如我想把最新文章widget在两栏的时候放到左边的靠近上方的位置。

先在 includes/helpers/layout.js 中添加函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
hexo.extend.helper.register('get_widgets_by_columns', function(position, column) {
const hasWidgets = hexo.extend.helper.get('has_config').bind(this)('widgets');
if (!hasWidgets) {
return [];
}
const widgets = hexo.extend.helper.get('get_config').bind(this)('widgets');
for(var i=0; i<widgets.length; ++i){
if(widgets[i].type === 'recent_posts'){
widgets[i].position = (column === 2 ? 'left' : 'right');
}
}
return widgets.filter(widget => widget.hasOwnProperty('position') && widget.position === position);
});

然后再修改layout/common/widget.ejs中的get_widgets get_widgets_by_columns` 函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="column <%= side_column_class() %> <%= visibility_class() %> <%= order_class() %> column-<%= position %> <%= sticky_class(position) %>">
- <% get_widgets(position, column_count()).forEach(widget => {%>
+ <% get_widgets_by_columns(position, column_count()).forEach(widget => {%>
<%- partial('widget/' + widget.type, { widget, post: page }) %>
<% }) %>
<% if (position === 'left') { %>
<div class="column-right-shadow <%= (page.__page !== true && page.__post !== true) ? 'is-hidden-widescreen' : '' %> <%= sticky_class('right') %>">
- <% get_widgets('right', column_count()).forEach(widget => { if(widget.type !== 'tag'){%>
+ <% get_widgets_by_columns('right', column_count()).forEach(widget => { if(widget.type !== 'tag'){%>
<%- partial('widget/' + widget.type, { widget, post: page }) %>
<% }}) %>
</div>
<% } %>
</div>

随机图片路径

includes/helpers/page.js 中添加两个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
hexo.extend.helper.register('has_random_recent_thumbnail', function (post) {
const getConfig = hexo.extend.helper.get('get_config').bind(this);
return getConfig('article.random_recent_thubnail', true);
});

hexo.extend.helper.register('get_random_recent_thumbnail', function (post) {
const autothubnail = hexo.extend.helper.get('has_random_recent_thumbnail').bind(this)(post);
var url = "images/thumbnail.svg";
if(autothubnail){
url = "/photos/life/image" + Math.floor(Math.random()*26) + ".jpg";
}
return this.url_for(url);
});

注意上面的 /photos/post_w 文件夹中的图片名字的规则,必须是数字递增,这里的23是该文件夹中的图片数量,图片序列下标从0开始。

_config.yml 中添加 article setting

1
2
article:
random_recent_thubnail: true

修改 layout/widget/recent_posts.ejs 文件:

1
2
3
4
5
6
7
8
9
- <% if(!has_config('thumbnail') || get_config('thumbnail') !== false) { %>
+ <% if (!has_config('article.random_recent_thubnail') || get_config('article.random_recent_thubnail') !== false) { %>
<a href="<%- url_for((post.link?post.link:post.path)) %>" class="media-left">
<p class="image is-64x64">
- <img class="thumbnail" src="<%= get_thumbnail(post) %>" alt="<%= post.title %>">
+ <img class="thumbnail" src="<%= get_random_recent_thumbnail(post) %>" alt="<%= post.title %>">
</p>
</a>
<% } %>

修改Gallery样式

1
2
3
4
5
<div class="justified-gallery">
![Elephant](/hexo-theme-icarus/gallery/animals/elephant.jpeg)
......

</div>

在icarus中有两个gallery插件,一个是 light Gallery 另一个是 justified Gallery

前者是一个轻量级的模块化、响应式的灯箱画廊,它允许您创建美丽的图像和视频画廊。借助缩略图插件的帮助,还允许您创建缩略图画廊。它支持触摸屏设备上滑动导航以及桌面设备的鼠标拖动,还允许用户浏览缩略图和原图之间通过滑动手指或鼠标拖动。

1
2
3
4
5
6
7
8
9
document.addEventListener('DOMContentLoaded', function () {
if (typeof ($.fn.lightGallery) === 'function') {
- $('.article').lightGallery({ selector: '.gallery-item'});
+ $('.article').lightGallery({ selector: '.gallery-item', loop: true, escKey: true, keyPress: true});
}
if (typeof ($.fn.justifiedGallery) === 'function') {
$('.justified-gallery').justifiedGallery({rowHeight:160, margins:4});
}
});

例如上面我添加了几项配置,灯箱画廊有很多配置的,一些核心配置如下:

参数类型默认值描述
modestring‘lg-slide’图片过渡的动画类型。可用的动画有:'lg-slide''lg-fade''lg-zoom-in''lg-zoom-in-big''lg-zoom-out''lg-zoom-out-big''lg-zoom-out-in''lg-zoom-in-out''lg-soft-zoom''lg-scale-up''lg-slide-circular''lg-slide-circular-vertical''lg-slide-vertical''lg-slide-vertical-growth''lg-slide-skew-only''lg-slide-skew-only-rev''lg-slide-skew-only-y''lg-slide-skew-only-y-rev''lg-slide-skew''lg-slide-skew-rev''lg-slide-skew-cross''lg-slide-skew-cross-rev''lg-slide-skew-ver''lg-slide-skew-ver-rev''lg-slide-skew-ver-cross''lg-slide-skew-ver-cross-rev''lg-lollipop''lg-lollipop-rev''lg-rotate''lg-rotate-rev''lg-tube'
cssEasingstring‘ease’easing过渡动画类型。
speednumber600过渡动画的持续时间。单位毫秒。
heightstring‘100%’图片画廊的高度。
widthstring‘100%’图片画廊的宽度。
addClassstring‘’为画廊添加自定义的class。
startClassstring‘lg-start-zoom’画廊的开始动画类型。
backdropDurationnumber150Lightgallery backdrop transtion duration
hideBarsDelaynumber6000隐藏图片画廊控制按钮的延迟时间,单位毫秒。
useLeftbooleanfalse强制lightgallery使用left 属性来代替transform。
closablebooleantrue允许用户点击暗处关闭图片画廊。
loopbooleantrue是否循环播放。
escKeybooleantrue是否允许通过”Esc”键来关闭图片画廊。
keyPressbooleantrue是否允许键盘导航。
controlsbooleantrue是否显示前后导航按钮。
slideEndAnimatoinboleantrue是否允许slideEnd 动画。
hideControlOnEndbooleanfalse如果设置为false,第一幅和最后一幅图片不显示前后导航按钮。
getCaptionFromTitleOrAltbooleantrue从图片的alt或title标签获取图片描述信息。
appendSubHtmlTostring‘.lg-sub-html’指定添加sub-html:'.lg-sub-html''.lg-item'
subHtmlSelectorRelativebooleanfalse如果使用”data-sub-html”选择器作为当前项目的源,设置为true。
preloadnumber1预加载slider的数量。
showAfterLoadbooleantrue是否在完全加载后显示内容。
selectorstring‘’自定义选择器来替代子元素。
selectWithinstring‘’By default selectror element is taken from only inside the gallery element. Instead of that you can tell lightgallery to select element within a specific
nextHtmlstring‘’Next按钮的html标记。
prevHtmlstring‘’Prev按钮的html标记。
indexnumber0设置被立刻加载的图片/视频的索引。
iframeMaxWidthstring‘100%’设置iframe的最大宽度。
downloadbooleantrue是否使用下载按钮。
counterbooleantrue是否显示图片的总数和当前图片的索引。
appendCounterTostring‘.lg-toolbar’指定被添加的计数器。
swipeThresholdnumber50触摸滑动的阈值。
enableDragbooleantrue在桌面设备是否允许鼠标拖动。
enableTouchbooleantrue是否允许移动触摸。
dynamicbooleanfalse通过编程的方式动态调用插件。
dynamicElarray[]代表画廊元素的数组。

我博客的相册使用的是后者,后者是我喜欢的瀑布流样式,但是默认的这个样式高度和间隙我不是很喜欢,所以下面修改一下文件 source/js/gallery.js 代码如下:

1
2
3
4
5
6
7
8
9
document.addEventListener('DOMContentLoaded', function () {
if (typeof ($.fn.lightGallery) === 'function') {
$('.article').lightGallery({ selector: '.gallery-item' });
}
if (typeof ($.fn.justifiedGallery) === 'function') {
- $('.justified-gallery').justifiedGallery();
+ $('.justified-gallery').justifiedGallery({rowHeight:160, margins:4});
}
});

上面修改了瀑布流布局的每行高度为160px,间隔为4px。

事实上justifiedGallery有很多可设置选项,具体可参考官方文档:http://miromannino.github.io/Justified-Gallery/getting-started/

文章图片居中

主题文章图片居中问题的解决办法很简单,只需要修改 source/js/main.js 的文件内容如下:

1
2
3
4
5
6
7
8
9
10
$('.article img:not(".not-gallery-item")').each(function () {
// wrap images with link and add caption if possible
if ($(this).parent('a').length === 0) {
- $(this).wrap('<a class="gallery-item" href="' + $(this).attr('src') + '"></a>');
+ $(this).wrap('<a class="gallery-item" style="display:block;text-align:center;" href="' + $(this).attr('src') + '"></a>');
if (this.alt) {
$(this).after('<div class="has-text-centered is-size-6 has-text-grey caption">' + this.alt + '</div>');
}
}
});

还有一种比较优雅的方式就是修改 layout/css/style.styl 文件的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.article
.article-meta
margin-bottom: 0.5rem !important
.content
font-size: 1.1rem
blockquote.pullquote
float: right
max-width: 50%
font-size: 1.15rem
position: relative
+ a
+ img
+ margin: auto
+ display: block

最后

这个主题也存在几个问题,比如文章页的表格影响小尺寸上响应式布局会有超出内页的问题,有时候打开页面布局会出问题。

目前(2019年6月26日)作者已经修复上面的超出内页问题,详细请查看Github上面的issues#480,另一个问题也已经提了issues#481,你如果关心可以持续关注。

评论

Ajax Android AndroidStudio Animation Anroid Studio AppBarLayout Babel Banner Buffer Bulma ByteBuffer C++ C11 C89 C99 CDN CMYK COM1 COM2 CSS Camera Raw, 直方图 Chrome ContentProvider CoordinatorLayout C语言 DML DOM Dagger Dagger2 Darktable Demo Document DownloadManage ES2015 ESLint Element Error Exception Extensions File FileProvider Flow Fresco GCC Git GitHub GitLab Gradle Groovy HTML5 Handler HandlerThread Hexo Hybrid I/O IDEA IO ImageMagick IntelliJ Intellij Interpolator JCenter JNI JS Java JavaScript JsBridge Kotlin Lab Lambda Lifecycle Lint Linux Looper MQTT MVC MVP Maven MessageQueue Modbus Momentum MySQL NDK NIO NexT Next Nodejs ObjectAnimator Oracle VM Permission PhotoShop Physics Python RGB RS-232 RTU Remote-SSH Retrofit Runnable RxAndroid RxJava SE0 SSH Spring SpringBoot Statubar Task Theme Thread Tkinter UI UIKit UML VM virtualBox VS Code VUE ValueAnimator ViewPropertyAnimator Vue Web Web前端 Workbench api apk bookmark by关键字 compileOnly css c语言 databases demo hexo hotfix html iOS icarus implementation init jQuery javascript launchModel logo merge mvp offset photos pug query rxjava2 scss servlet shell svg tkinter tomcat transition unicode utf-8 vector virtual box vscode 七牛 下载 中介者模式 串口 临潼石榴 主题 书签 事件 享元模式 仓库 代理模式 位运算 依赖注入 修改,tables 光和色 内存 内核 内部分享 函数 函数式编程 分支 分析 创建 删除 动画 单例模式 压缩图片 发布 可空性 合并 同向性 后期 启动模式 命令 命令模式 响应式 响应式编程 图层 图床 图片压缩 图片处理 图片轮播 地球 域名 基础 增加 备忘录模式 外观模式 多线程 大爆炸 天气APP 太白山 头文件 奇点 字符串 字符集 存储引擎 宇宙 宏定义 实践 属性 属性动画 岐山擀面皮 岐山肉臊子 岐山香醋 工具 工厂模式 年终总结 开发技巧 异常 弱引用 恒星 打包 技巧 指针 插件 摄影 操作系统 攻略 故事 数据库 数据类型 数组 文件 新功能 旅行 旋转木马 时序图 时空 时间简史 曲线 杂谈 权限 枚举 架构 查询 标准库 标签选择器 样式 核心 框架 案例 桥接模式 检测工具 模块化 模板引擎 模板方法模式 油泼辣子 泛型 洛川苹果 浅色状态栏 源码 源码分析 瀑布流 热修复 版本 版本控制 状态栏 状态模式 生活 留言板 相册 相对论 眉县猕猴桃 知识点 码云 磁盘 科学 笔记 策略模式 类图 系统,发行版, GNU 索引 组件 组合模式 结构 结构体 编码 网易云信 网格布局 网站广播 网站通知 网络 美化 联合 膨胀的宇宙 自定义 自定义View 自定义插件 蒙版 虚拟 虚拟机 补码 补齐 表单 表达式 装饰模式 西安 观察者模式 规范 视图 视频 解耦器模式 设计 设计原则 设计模式 访问者模式 语法 责任链模式 贪吃蛇 转换 软件工程 软引用 运算符 迭代子模式 适配器模式 选择器 通信 通道 配置 链表 锐化 错误 键盘 闭包 降噪 陕西地方特产 面向对象 项目优化 项目构建 黑洞
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×