## 前言
很荣幸被作者大佬邀请谈谈自己的修改心得,也很感谢午后大佬能做出如此漂亮的主题。
首先说明Vuepress的vuepress-theme-reco
主题已经很完美了,主要因为我已经有了自己的生活博客小弋の生活馆 (opens new window),还缺一个文档类的技术博客,所以为了更加适合自己查阅技术文档,对作者的主题进行一点小小的优化(个人向,比较主观):
- 更换主题到本地后,无法直接通过npm install直接更新主题
- 进一步对侧边栏优化,右侧滚动栏优化,字体优化
- 增加各种好玩实用的插件
- 取消了博客页面,直接转跳到文档页面
- 个人向修改,不喜勿喷
我的博客:https://lovelijunyi.gitee.io/blog/
# 更换主题为本地
- 与hexo不一样,正常的主题文件会被安装到
node_modules
文件夹中。如果之前vuepress-theme-reco
安装正确的话,可以在node_modules
文件夹中找到改文件。所以如果不把主题文件放到本地,我们每次执行npm install的时候,新的文件就会把我们魔改过的文件覆盖掉。 - 接着不得不谈一下主题的启动流程:如果config没指定,系统会默认会检查
.vuepress/theme
,如果还没有就,直接用默认主题。 - 所以只要把下载(或者直接从
node_modules
中复制)下来的文件夹更名为theme,粘贴至 .vuepress文件夹下即可,如果在执行编译过程中,看到tip Apply local theme at xxx\Desktop\blog\.vuepress\theme...
相关提示,就说明从theme文件夹启动成功 - 整个目录结构如下
Dev
├─── docs
│ └── .vuepress // 配置目录
│ │ ├── public // 静态资源
│ │ ├── theme // 主题
│ │ │ ├── components // 组件
│ │ │ ├── global-components // 全局组件
│ │ │ ├── layouts // 布局(包括首页在内)
│ │ │ ├── styles // 样式
│ │ │ ├── util // 工具
│ │ │ ├── index.js // 入口配置
│ │ │ ├── noopModule.js // 依赖注入
│ │ │ ├── package.json // 主题依赖
│ │ │ ├── README.md // 主题说明
│ │ └── config.js
│ ├── FAQ // 求索模块
│ ├── Store // 仓库模块
│ ├── Thought // 随笔模块
│ └── README.md // 博客首页
└── package.json
# 外挂组件修改
如果你不满足于主题提供的默认样式,VuePress 提供了一些简单的接口文件,可以让你能够很方便地定制你自己想要的效果,和hexo外挂组件修改一样,这类修改无需改动源码,上手简单。
# 修改主题颜色
我这里暂时没有修改,如有需要可以通过配置 .vuepress/styles/palette.styl
来快速修改主题的一些颜色属性。(如果不存在该目录和文件就创建一个)
// 默认值
$accentColor = #3eaf7c // 主题颜色
$textColor = #2c3e50 // 文本颜色
$borderColor = #eaecef // 边框线颜色
$codeBgColor = #282c34 // 代码块背景色
$backgroundColor = #ffffff // 悬浮块背景色
# 修改主题样式
你可以创建一个 .vuepress/styles/index.styl
文件以方便地添加额外样式。这是一个 Stylus 文件,但你也可以使用正常的 CSS 语法,我的修改如下,主要是改进了文档页面的可读性和操作性:
// 侧边栏样式
// 左侧侧边栏标题
.sidebar > .sidebar-links > li > a.sidebar-link {
font-size: 1.5em !important;
margin-left: -1em;
}
// 右侧文章标题导航栏
a.sidebar-link {
font-size: 16px !important;
}
// 左侧边栏标题字体大小样式
.sidebar-heading span{
font-size: 1.2em;
font-weight: bold;
}
.sidebar-heading.open span{
font-weight: bold;
}
// 左侧边栏展开文章的字体大小
a.sidebar-link.active {
color: #070808 !important;
font-size: 14px !important;
background: #c3d4b742 !important;
}
.sidebar-sub-headers a.sidebar-link {
margin: 0 1rem 0 1rem !important;
}
// 分组的透明度修改,未生效
.sidebar-group.is-sub-group > .sidebar-heading:not(.clickable){
opacity: 0.5;
}
// 去除左上角标题,作者,标签等
.page .page-title {
display: none;
}
效果如下
其他修改,主要参照znote大佬,修改如下(可选):
blockquote {
background-color: transparent !important;
margin: 20px !important;
padding: 0 !important;
font-size: 1rem !important;
color: #999 !important;
border-left: .25rem solid #dfe2e5 !important;
margin-left: 0 !important;
padding-left: 1rem !important;
}
// tip,warning,danger容器样式
.custom-block.tip {
background-color: #d4d4d452 !important;
}
.custom-block.warning {
background-color: #ffa16d47 !important;
}
.custom-block.danger {
background-color: #f9b4b457 !important;
}
// details容器样式
summary {
font-weight: 550;
font-size: 16px;
margin-top: 0.2rem;
padding-top: 11px;
padding-bottom: 11px;
background-color: #75826b42;
border-radius: 5px;
}
// 时间线样式
.timeline-wrapper .year {
margin: 80px 0px 20px !important;
font-size: 27px !important;
}
.timeline-wrapper .year-wrapper li {
padding: 10px 20px 10px !important;
border-bottom: 2px solid #999da06b !important;
background: #c1c1e626;
border-radius: 5rem;
margin: 5px 0px;
transition: all .5s;
}
.timeline-wrapper .year-wrapper li:hover {
transform: translate(50px,0);
transition: all .5s;
}
.timeline-wrapper .year-wrapper li .date {
width: 43px !important;
font-size: 13px !important;
}
.timeline-wrapper .year-wrapper li .date:before {
top: 22px !important;
border: 1px solid !important;
}
.timeline-wrapper:after {
background: skyblue !important;
}
.timeline-wrapper .desc:before, .timeline-wrapper .year:before {
background: cadetblue !important;
}
//主页,评论偏左
.page, .password-wrapper-in {
margin-left: 8rem !important;
}
.comments-wrapper {
padding: 2rem 2rem 2rem 10rem !important;
}
#valine .vwrap .vedit #veditor{
background: url('/znote/img/other/comment.png')
background-position: 90% 60%
background-size: 16rem 10rem
background-repeat: no-repeat
}
$mobileSidebarWidth = $sidebarWidth * 0.82
// narrow desktop / iPad
@media (max-width: $MQNarrow)
.sidebar
font-size 15px
width $mobileSidebarWidth !important;
.page, .password-wrapper-in
margin-left $mobileSidebarWidth !important;
.comments-wrapper
padding: 2rem 2rem 2rem $mobileSidebarWidth*1.1 !important;
// wide mobile
@media (max-width: $MQMobile)
.sidebar
top 0
padding-top $navbarHeight !important;
transform translateX(-100%)
transition transform .2s ease
.page, .password-wrapper-in
margin-left 0 !important;
.comments-wrapper
padding: 2rem 2rem 2rem 2rem !important;
.theme-container
&.sidebar-open
.sidebar
transform translateX(0) !important;
&.no-navbar
.sidebar
padding-top: 0 !important;
.password-shadow
padding-left 0 !important;
// narrow mobile
@media (max-width: $MQMobileNarrow)
h1
font-size 1.9rem
.content__default
div[class*="language-"]
margin 0.85rem -1.5rem !important;
border-radius 0
//about me
@media (min-width: ($MQMobile + 1px))
.theme-container.no-sidebar
.sidebar
display none
.page, .password-wrapper-in
margin-left 0 !important;
.comments-wrapper
padding: 2rem 2rem 2rem 2rem !important;
//标签列表样式
.abstract-item {
background-color: #acdcfd3d !important;
transition: all .5s;
}
.abstract-item:hover {
transform: scale(1.02);
transition: all .5s;
}
//滚动条样式
::-webkit-scrollbar
width: 6px !important;
/*滚动条的设置*/
::-webkit-scrollbar-thumb {
background-color:#94989c8c !important;
background-clip:padding-box !important;
-webkit-border-radius: 10em !important;
-moz-border-radius: 10em !important;
border-radius: 10em !important;
}
/*滚动条凹槽的颜色,还可以设置边框属性 */
::-webkit-scrollbar-track-piece {
background-color:transparent !important;
-webkit-border-radius: 0em !important;
-moz-border-radius: 0em !important;
border-radius: 0em !important;
}
/*滚动条鼠标移上去*/
::-webkit-scrollbar-thumb:hover {
background-color:#bbb !important;
}
//navbar字体大小
.navbar .links
font-size: 15.5px !important;
//容器样式
.theorem
margin 1rem 0
padding .1rem 1.5rem
border-radius 0.4rem
background-color #c9daea61
.title
font-weight bold
.custom-block
&.right
color transparentify($textColor, 0.4)
font-size 0.9rem
text-align right
@require './markdown-container'
这里作者还引入了markdown-container.styl,需要的自行引入
.cardListContainer
margin .7rem 0
&>:not(.card-list)
display none
.card-list
margin -0.35rem
display: flex;
flex-wrap: wrap;
align-items: flex-start;
.card-item
width calc(100%/3 - .7rem)
margin auto
background var(--bodyBg)
border-radius 3px
color var(--textColor)
display flex
box-shadow 1px 1px 2px 0 rgba(0,0,0,.06)
&:hover
text-decoration none
img
transform rotate(8deg) scale(1.1, 1.1)
box-shadow 3px 2px 7px rgba(0, 0, 0, 0.15)
div p
text-shadow 3px 2px 5px rgba(0, 0, 0, 0.15)
img
width 60px
height 60px
border-radius 50%
border 2px solid #fff
margin 1rem
margin-right 0
box-shadow 3px 2px 5px rgba(0, 0, 0, 0.08)
transition all .4s
div
flex 1
display inline-block
float right
padding 1rem 0
p
margin 0
padding 0 1rem
transition text-shadow .4s
text-align center
.name
margin .2rem 0 .3rem 0
.desc
font-size .8rem
line-height 1.1rem
opacity .8
margin-bottom .2rem
.card-item.row-1
width calc(100% - .7rem)
img
margin-left 2rem
.card-item.row-2
width calc(100%/2 - .7rem)
img
margin-left 1.5rem
.card-item.row-3
width calc(100%/3 - .7rem)
.card-item.row-4
width calc(100%/4 - .7rem)
.cardImgListContainer
margin 1rem 0
&>:not(.card-list)
display none
.card-list
margin -0.5rem
display: flex;
flex-wrap: wrap;
align-items: flex-start;
.card-item
width calc(100%/3 - 1rem)
margin .5rem
background var(--mainBg)
border 1px solid rgba(0,0,0,0.08)
box-sizing: border-box
border-radius 3px
overflow hidden
color var(--textColor)
box-shadow 2px 2px 10px rgba(0,0,0,.04)
display flex
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
align-content: stretch;
transition: box-shadow .3s
&:hover
box-shadow 1px 1px 20px rgba(0,0,0,.07)
.box-img
overflow hidden
position relative
background #000
img
display block
width 100%
height auto
transition: all .3s
&:hover
img
transform: scale(1.1, 1.1)
opacity .75
a
color var(--textColor)
transition: color .3s
&:hover
color $accentColor
text-decoration none
.box-info
padding: .8rem 1rem
p
margin 0
.desc
margin-top: .3rem
opacity .8
font-size: .9rem
line-height: 1.1rem
.box-footer
overflow hidden
padding: .8rem 1rem
border-top: 1px solid rgba(0,0,0,0.05)
img
width 1.8rem
height 1.8rem
border-radius 50%
float left
span
line-height 1.8rem
float left
margin-left: .6rem
font-size: .8rem
.card-item.row-1
width calc(100% - 1rem)
.card-item.row-2
width calc(100%/2 - 1rem)
.card-item.row-3
width calc(100%/3 - 1rem)
.card-item.row-4
width calc(100%/4 - 1rem)
.theme-mode-dark
.cardImgListContainer
.card-list
.card-item
border-color: var(--borderColor)
.box-footer
border-color: var(--borderColor)
// 卡片列表的响应
@media (max-width: 900px)
.cardListContainer
.card-list
.card-item.row-4
width calc(100%/3 - .7rem)
.cardImgListContainer
.card-list
.card-item.row-4
width calc(100%/3 - 1rem)
@media (max-width: 720px)
.cardListContainer
.card-list
.card-item.row-3, .card-item.row-4
width calc(100%/2 - .7rem)
img
margin-left 1.5rem
.cardImgListContainer
.card-list
.card-item.row-3, .card-item.row-4
width calc(100%/2 - 1rem)
@media (max-width: 500px)
.cardListContainer
.card-list
.card-item.row-1, .card-item.row-2, .card-item.row-3, .card-item.row-4
width calc(100% - .7rem)
img
margin-left 1.5rem
.cardImgListContainer
.card-list
.card-item.row-1, .card-item.row-2, .card-item.row-3, .card-item.row-4
width calc(100% - 1rem)
是否可以将颜色与样式写在同一个文件?
不可以将颜色与样式写在同一个文件中,VuePress 会先解析 palette.styl
中的全局变量,之后作用于主题的各个样式中,最后才解析 index.styl
,以覆盖主题默认的样式。
# 引用脚本与样式
# 操作说明
这个操作类似butterfly主题中的inject,你可以通过配置 .vuepress/config.js
中的 head
来引入脚本与样式。
通过外挂css和js来对主题样式曾铁,例如点击效果,花瓣雨等等特效。
module.exports = {
head: [
["link", { rel: "stylesheet", href: "https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css" }],
["script", { src: "scripts/demo.js" }]
]
}
比如上面的配置就会被解析为
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css">
<script src="scripts/demo.js"></script>
</head>
关于 head
的详细配置说明请参考官方文档 head 配置 (opens new window)
# 引入鼠标点击效果
在.vuepress\public\js
文件夹下创建MouseClickEffect.js
文件,填入以下代码
var a_idx = 0;
function getRandom(max, min) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
jQuery(document).ready(function ($) {
$("body").click(function (e) {
var a = new Array("富强", "民主", "文明", "和谐", "自由", "平等", "公正", "法治", "爱国", "敬业", "诚信", "友善");
var $i = $("<span/>").text(a[a_idx]);
a_idx = (a_idx + 1) % a.length;
var x = e.pageX,
y = e.pageY;
$i.css({
"z-index": 999999999999999999999999999999999999999999999999999999999999999999999,
"top": y - 20,
"left": x,
"position": "absolute",
"font-weight": "bold",
"color": `rgb(${getRandom(255,0)},${getRandom(255,0)},${getRandom(255,0)})`,
"user-select": 'none',
"cursor": 'default'
});
$("body").append($i);
$i.animate({
"top": y - 180,
"opacity": 0
},
1500,
function () {
$i.remove();
});
});
});
然后在主题配置文件config.js
下的head
引入以上js,这里的jquery必须引入,鼠标点击代码才能生效
head: [
// 网页标签栏图标
['link', { rel: 'icon', href: '/vuepress/favicon.ico' }],
// 移动栏优化
['meta', { name: 'viewport', content: 'width=device-width,initial-scale=1,user-scalable=no' }],
// 引入jquery
["script", {
"language": "javascript",
"type": "text/javascript",
"src": "https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"
}],
// 引入鼠标点击脚本
["script", {
"language": "javascript",
"type": "text/javascript",
"src": "/js/MouseClickEffect.js"
}]
],
# 文章中引入样式和脚本
有时,你可以只想在当前页面应用一些 JavaScript
或者 CSS
,在这种情况下,你可以直接在 Markdown
文件中使用原生的 或者 标签,它们将会从编译后的 HTML 文件中提取出来,并作为生成的 Vue 单文件组件的和标签。
输入
<p class="demo" :class="$style.example"></p>
<style module>
.example {
color: #41b883;
}
</style>
<script>
export default {
props: ['slot-key'],
mounted () {
document.querySelector(`.${this.$style.example}`)
.textContent = '这个块是被内联的脚本渲染的,样式也采用了内联样式。'
}
}
</script>
输出
这个块是被内联的脚本渲染的,样式也采用了内联样式。
# 推荐插件类
# 我的插件配置
所有插件必须要用中括号包起来,别问为啥,吃过苦头😵
module.exports = [
// 流程图插件
['flowchart'],
// 标签加强
["vuepress-plugin-boxx" ],
// 动态标题
["dynamic-title",
{
showIcon: "vuepress/smile.ico",
showText: "(/≧▽≦/)欢迎帅哥美女!",
hideIcon: "vuepress/cry.ico",
hideText: "(●—●)呜呜,不要走嘛!!",
recoverTime: 2000
}],
// 更新刷新插件
['@vuepress/pwa', {
serviceWorker: true,
updatePopup: {
message: "发现新内容可用",
buttonText: "刷新"
}
}],
// 代码复制弹窗插件
["vuepress-plugin-nuggets-style-copy", {
copyText: "复制代码",
tip: {
content: "复制成功!"
}
}],
// 音乐插件
['meting', {
//metingApi: "https://meting.sigure.xyz/api/music",
meting: {
// 网易
server: "netease",
// 读取歌单
type: "playlist",
mid: "696441716",
},
// 不配置该项的话不会出现全局播放器
aplayer: {
// 吸底模式
fixed: true,
mini: true,
// 自动播放
autoplay: true,
// 歌曲栏折叠
listFolded:true,
// 颜色
theme: '#f9bcdd',
// 播放顺序为随机
order: 'random',
// 初始音量
volume: 0.1,
// 关闭歌词显示
lrcType: 0
},
mobile :{
// 手机端去掉cover图
cover: false,
}
}]
/* 弹窗公告插件
[
"@vuepress-yard/vuepress-plugin-window"
], */
/* 音乐插件
["@vuepress-reco/vuepress-plugin-bgm-player",
{
audios: [
// 网络文件示例
{
name: '年轮',
artist: '张碧晨',
url: 'https://cdn.jsdelivr.net/gh/fudalijunyi/cdn/MP3/年轮.mp3',
cover: 'https://cdn.jsdelivr.net/gh/fudalijunyi/picture-bed/img/20200715154924.png'
}
] ,
// 自动缩小
autoShrink:true ,
// 悬浮窗模式,吸边
shrinkMode: 'float' ,
// 悬浮窗位置
floatStyle:{ bottom: '10px', 'z-index': '999999' },
}],*/
]
# 音乐插件
目前音乐插件有两种:
- bgm-player (opens new window),一款简洁易用的音乐插件,优势是好看,其他一无是处了🙂
- music-bar (opens new window),一个程序猿自己开发的插件,除本地,网络音频之外还支持从平台歌单获取链接(目前仅支持网易云音乐),缺点是丑了点,支持一下这位老哥👯
- meting (opens new window),在hexo上就一直用的插件,功能强大,配置丰富,目前应该最大强大的音乐插件了,我用的就是这个,强推👍,还支持在markdown中直接插入,操作如下
<Meting server="netease"
type="playlist"
mid="2539599584"
:lrc-type="3"/>
这里再推荐一个音乐外链网:http://music.xf1433.com/
# 趣味标题插件
这个在hexo已经很熟悉了,主要在标签栏当时选中和离开页面时会有变化
# 安装
npm i vuepress-plugin-dynamic-title -D
# 使用
module.exports = {
plugins: [
[
"dynamic-title",
{
showIcon: "/favicon.ico",
showText: "(/≧▽≦/)咦!又好了!",
hideIcon: "/failure.ico",
hideText: "(●—●)喔哟,崩溃啦!",
recoverTime: 2000
}
]
]
}
# Boxx插件
参考:https://zpj80231.gitee.io/znote/views/front-end/vuepress-plugin-boxx.html
可以为博客文章自动随机添加名人名言或其他,可自定义样式和内容
# 安装
- 在文件
package.json
中的devDependencies
下加入"vuepress-plugin-boxx": "0.0.7"
:
"devDependencies": {
"vuepress-plugin-boxx": "0.0.7"
}
- 在 vuepress 的
config.js
中配置plugins
:
plugins: [
["vuepress-plugin-boxx"]
],
- 在
package.json
目录下执行命令:npm install
- 正常启动项目,接着如下使用即可
# 使用
- 引入:只需在你想要插入的地方加入
<Boxx/>
即可(如顶部所示) - 内容:默认随机展示名人名句,支持自定义
- 样式:有三种样式,默认为 tip 样式,支持自定义
- 注意:除
<Boxx/>
这个标签是必须外,标签属性均为可选,所有标签属性会在下文中详细介绍
# 默认样式
# 自定义标题和内容
- 如果默认的名人名句不满足需求的话,自定义只需指定两个属性
title
和content
的值
Name | Type | Description |
---|---|---|
title | String | 要展示的title 的内容,支持html标签 |
content | String | 要展示的content 的内容,支持html标签 |
- 当然你也可以只输入
title
或content
,如下:
# 自定义样式
- 可以通过以下几个属性实现
Name | Type | Description |
---|---|---|
blockStyle | Object | 整体块元素的样式 |
titleStyle | Object | 只针对title 的样式 |
contentStyle | Object | 只针对content 的样式 |
changeTime | Number | 以毫秒值为单位的动态变化时间,顶部为例 |
需要注意的是:属性值传输的对象只能通过v-bind:
绑定来实现
- 以下是对如上样式的示例,在Markdown中这样书写即可:
<marquee>
<Boxx :blockStyle="blockStyle" />
<Boxx type="warning" :blockStyle="titleStyle" :titleStyle="titleStyle" changeTime="1000" title="我是一个大大的且变化的 title"/>
<Boxx type="danger" :blockStyle="contentStyle" :contentStyle="contentStyle" content="我是一个小小的<br><marquee>content</marquee>"/>
</marquee>
<script>
export default {
data() {
return {
blockStyle: {'background':'#eee','color':'red'},
titleStyle: {'margin-right': '10%','font-size':'16px'},
contentStyle: {'margin-right': '20%','font-size':'10px',
"margin-top": "1rem","margin-bottom": "0.4rem"},
}
}
}
</script>
# PWA插件
# 安装
npm install -D @vuepress/plugin-pwa
# 使用
本选项开启了一个用于刷新内容的弹窗。这个弹窗将会在站点有内容更新时显示出来,并提供了一个 refresh
按钮,允许用户立即刷新内容。
如果没有“刷新”按钮,则只有在所有的 Clients (opens new window) 被关闭后,新的 Service Worker 才会处于活动状态。这意味着用户在关闭你网站的所有标签之前无法看到新内容。但是
refresh
按钮会立即激活新的 Service Worker。
['@vuepress/pwa', {
serviceWorker: true,
updatePopup: {
message: "发现新内容可用",
buttonText: "刷新"
}
}],
# 复制弹窗插件
# 安装
npm install -D vuepress-plugin-nuggets-style-copy
# 使用
["vuepress-plugin-nuggets-style-copy", {
copyText: "复制代码",
tip: {
content: "复制成功!"
}
}]
# 公告弹窗插件
# 演示
# 下载
https://www.npmjs.com/package/@vuepress-yard/vuepress-plugin-window
# 修改源码
不到迫不得已还是不要修改源码,我主要是因为使用分组的侧边栏后,如果嵌套的内容标题下,不加这个path参数(如果加了每次点侧边栏标题都会转跳,非常难受),颜色就会偏淡,通过上文中index.styl
无论如何也不能加深
children: [
{
title: 'Matplotlib', // 必要的
//path: '', // 可选的, 标题的跳转链接,应为绝对路径且必须存在
collapsable: true, // 可选的, 默认值是 true,
children: [
'Python/Matplotlib/Matplotlib绘图指南',
'webc/01.Requests使用技巧',
'webc/02.数据存入Excel',
]
通过全局搜索,终于找到在源码文件\xxx\blog\node_modules\vuepress-theme-reco\components\SidebarGroup.vue
中发现问题,罪魁祸首就是这个opacity 0.5
,致此,将其改成1即可,虽然简单,但是对于有页面强迫症的我,确实是极大的舒适。
.sidebar-group
background var(--background-color)
.sidebar-group
padding-left 0.5em
&:not(.collapsable)
.sidebar-heading:not(.clickable)
cursor auto
color var(--text-color)
// refine styles of nested sidebar groups
&.is-sub-group
padding-left 0
& > .sidebar-heading
font-size 0.95em
line-height 1.4
font-weight normal
padding-left 2rem
&:not(.clickable)
opacity 0.5
& > .sidebar-group-items
padding-left 1rem
& > li > .sidebar-link
font-size: 0.95em;
# 参考资料
znote:https://zpj80231.gitee.io/znote/views/front-end/vuepress-plugin-boxx.html vuepress-theme-reco:http://v1.vuepress-reco.recoluan.com/