html
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Error</title>
|
||||||
|
<style>
|
||||||
|
html { color-scheme: light dark; }
|
||||||
|
body { width: 35em; margin: 0 auto;
|
||||||
|
font-family: Tahoma, Verdana, Arial, sans-serif; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>An error occurred.</h1>
|
||||||
|
<p>Sorry, the page you are looking for is currently unavailable.<br/>
|
||||||
|
Please try again later.</p>
|
||||||
|
<p>If you are the system administrator of this resource then you should check
|
||||||
|
the error log for details.</p>
|
||||||
|
<p><em>Faithfully yours, nginx.</em></p>
|
||||||
|
</body>
|
||||||
|
</html>
|
244
README.md
|
@ -1,2 +1,244 @@
|
||||||
# osredm_help
|
# 红山开源平台开源项目使用手册
|
||||||
|
## 1. 开源项目:项目管理
|
||||||
|
|
||||||
|
项目是用户创建的对应于一个小组或团队的协同实践社区,由项目管理员、开发人员和报告人员组成,提供问题跟踪、版本管理、里程碑、代码质量分析、资源托管、交流研讨等功能。
|
||||||
|
|
||||||
|
注意:未开展分组作业或项目开发的用户暂不涉及本章内容。
|
||||||
|
|
||||||
|
### 1.1 基本操作流程
|
||||||
|
|
||||||
|
开源项目是一种协同实践社区,支持团队和小组开展各种协作活动。 开源项目的典型操作流程如下:
|
||||||
|
|
||||||
|
1. 项目创建:团队(或小组)的核心成员首先创建一个项目。
|
||||||
|
|
||||||
|
2. 成员添加:通知团队其他成员在红山开源平台上注册(如已注册则忽略此步),将团队成员加入项目。
|
||||||
|
|
||||||
|
3. 问题跟踪:发布不同类型的问题,指派给责任人,并跟踪问题的解决进度。
|
||||||
|
|
||||||
|
4. 版本管理:基于Git版本库实现分布式版本控制。
|
||||||
|
|
||||||
|
5. 交流互动:基于讨论区等工具开展深度技术交流和研讨。 上述步骤的详细操作参见以下章节。
|
||||||
|
|
||||||
|
### 1.2 项目创建
|
||||||
|
|
||||||
|
项目包括创建:1、创建镜像项目;2、创建托管项目;3、创建组织。
|
||||||
|
|
||||||
|
1、创建镜像项目 点击右上角“⊕”,选择“创建镜像项目”,如下图所示: ![创建镜像项目](./static/img/3266.png) 填写项目基本信息,包括项目拥有者、镜像版本库地址、项目名称、项目简介等信息,并点击“创建项目”如下图所示: ![img](./static/img/3267.png)
|
||||||
|
|
||||||
|
2、创建托管项目 点击右上角“⊕”,选择“创建托管项目”,如下图所示: ![img](./static/img/3239.png) 填写项目基本信息,包括项目拥有者、项目名称、项目简介等信息,并点击“创建项目”如下图所示: ![img](./static/img/3240.png)
|
||||||
|
|
||||||
|
3、创建组织 点击右上角“⊕”,选择“创建组织”,如下图所示: ![img](./static/img/3241.png) 填写组织基本信息,包括组织名称、组织描述等,选择可见性,并上传头像后,点击“创建组织”如下图所示: ![img](./static/img/3242.png)
|
||||||
|
|
||||||
|
### 1.3 项目配置
|
||||||
|
|
||||||
|
项目的管理员可以对项目进行多种配置。 可配置的内容主要包括:
|
||||||
|
|
||||||
|
1. 项目基本信息:包括项目名称和简介,还包括项目是否公开、是否隐藏项目代码库以及删除项目
|
||||||
|
|
||||||
|
2. 成员管理:为项目添加各种角色的成员,点击“成员”标签页
|
||||||
|
|
||||||
|
3. 关联组织:将项目关联到相应的组织,点击“组织”标签页
|
||||||
|
|
||||||
|
4. 创建里程碑:为项目创建阶段性的产品版本,点击“里程碑”标签页
|
||||||
|
|
||||||
|
5. 创建版本库:为项目创建版本库(Git),点击“版本库”标签页
|
||||||
|
|
||||||
|
### 1.4 成员管理
|
||||||
|
|
||||||
|
项目管理员可以在项目配置中管理项目的成员。
|
||||||
|
|
||||||
|
1、点击“仓库设置”,进入标签页,选择左侧菜单栏的“协作者管理”,将看到如下页面: ![img](./static/img/3243.png) 2、在下图所示的搜索框内输入欲添加成员的用户名,如下图所示: ![img](./static/img/3244.png) 3、在搜索结果中选择想要添加的成员,点击“添加成员”,如下图所示: ![img](./static/img/3245.png) 4、成员添加成功后,可为其选择角色,包括管理员、开发者、报告者三种,如下图所示: ![img](./static/img/3246.png) 注意:项目成员的不同角色具有不同权限。 管理员:可以对项目中的所有模块进行操作。 开发者:不能对项目进行配置。 报告者:不能对版本库进行操作。
|
||||||
|
|
||||||
|
### 1.5 删除项目
|
||||||
|
|
||||||
|
管理员可以删除项目。步骤如下: 点击“仓库设置”,进入标签页,选择左侧菜单栏的“基本设置”,点击下方的“删除本仓库”,即可删除当前项目。 ![img](./static/img/3247.png)
|
||||||
|
|
||||||
|
### 1.6 发布问题
|
||||||
|
|
||||||
|
1、点击“易修(Issue)”,进入标签页,点击页面右侧的“创建任务”。 ![img](./static/img/3260.png) 2、填写任务标题及内容,选择指派成员、状态、类型、优先度等,点击“创建”。 ![img](./static/img/3251.png) ![img](./static/img/3252.png) ![img](./static/img/3253.png) ![img](./static/img/3254.png) ![img](./static/img/3255.png) 3、出现如下图所示信息时,表明问题发布成功。 ![img](./static/img/3256.png) 4、点击已发布的问题,进入问题详情页面,点击下图所示的评论区输入栏。 ![img](./static/img/3257.png) 5、点开输入栏后出现下图所示输入界面,输入想要评论的内容后,点击“评论”。 ![img](./static/img/3258.png) 6、出现如下图所示信息时,表明评论成功。 ![img](./static/img/3259.png) 注意: 每个问题都相当于一个可以进度追踪的帖子。因此支持回复、点赞、@等。 在问题截止日期的前一天,系统将对问题的发布人和被指派人发送提示消息。
|
||||||
|
|
||||||
|
### 1.7 新建里程碑
|
||||||
|
|
||||||
|
管理员可以新建里程碑。步骤如下: 1、点击“里程碑”,进入标签页,点击页面右侧的“新建里程碑”。 ![img](./static/img/3261.png) 2、填写新里程碑相关信息,包括标题、描述等,选择截止日期后,点击“创建里程碑”。 ![img](./static/img/3262.png) 3、出现如下图所示信息时,表明新的里程碑创建成功。 ![img](./static/img/3263.png) 注意:项目成员在发布问题时。将在“目标版本”属性中看到新建的版本。
|
||||||
|
|
||||||
|
### 1.8 关联里程碑
|
||||||
|
|
||||||
|
项目成员可以将项目问题关联到里程碑,从而使里程碑包含明确的任务列表。 步骤如下: 1、进入某个问题的页面,编辑“里程碑”属性,从“里程碑”下拉框中选择适当的里程碑,点击“提交”。 ![img](./static/img/3264.png) 2、出现如下图所示信息时,表明里程碑关联成功。 ![img](./static/img/3265.png)
|
||||||
|
|
||||||
|
## 2. 开源项目:版本管理
|
||||||
|
|
||||||
|
版本管理又称版本控制,是一种分布式协同编程的重要工具。没有掌握好版本管理工具,团队式协同开发是不可想象的。
|
||||||
|
|
||||||
|
红山开源平台集成了Gitlab版本管理系统,可以提供标准的Git版本库操作流程。 因此,在使用本平台提供的Git仓库时。可以直接参考本手册。也可以在互联网中搜索相关问题的解决方法。 详见:Git使用指南(https://git-scm.com/book/zh/v2)
|
||||||
|
|
||||||
|
注意:未开展项目开发的用户暂不涉及本章内容。
|
||||||
|
|
||||||
|
### 2.1 基本操作流程
|
||||||
|
|
||||||
|
Git版本库的使用非常灵活,功能非常强大,但其基本流程也是非常简单的:
|
||||||
|
|
||||||
|
1. 在平台上新建远程版本库或fork一个远程版本库
|
||||||
|
|
||||||
|
2. 将远程库clone到本地
|
||||||
|
|
||||||
|
3. 在本地库中创建分支(缺省为master)
|
||||||
|
|
||||||
|
4. 提交(commit)代码到本地分支
|
||||||
|
|
||||||
|
5. 推送(push)代码到远程库的分支/下拉(pull)远程库的代码到本地
|
||||||
|
|
||||||
|
6. 解决冲突
|
||||||
|
|
||||||
|
7. 合并分支
|
||||||
|
|
||||||
|
以上是一个在实际操作中反复进行的基本流程。
|
||||||
|
|
||||||
|
注意: 在多人协同编程的情况下,每个成员在开发自己的模块时,尽可能先从master或developer分支下载最新代码,并与本地分支合并,否则时间久了,合并分支将是一个灾难。 上连基本流程可以使用Git命令行客户端、Tortoise Git客户端等工具完成。
|
||||||
|
|
||||||
|
### 2.2 fork版本库
|
||||||
|
|
||||||
|
用户对某一个版本库的fork操作将会为该用户创建一个同名项目和同名版本库。
|
||||||
|
|
||||||
|
操作步骤:进入需要fork的版本库页面,点击右上角的Fork按钮即可。
|
||||||
|
|
||||||
|
注意: 任何用户都可以fork一个公开的版本库。 连续两次fork同一版本时,系统将直接跳转到第一次fork后的版本库。
|
||||||
|
|
||||||
|
### 2.3 新建版本库
|
||||||
|
|
||||||
|
管理员可以新建版本库。步骤如下:
|
||||||
|
|
||||||
|
1. 进入相应的开源项目的“项目配置”页面
|
||||||
|
2. 点击“版本库”标签页,点击“新建版本库”链接
|
||||||
|
3. 填写版本库名称后,点击“创建”
|
||||||
|
|
||||||
|
注意: 同一用户名下的版本不能重名。 平台也将在近期提供SSH访问方式。
|
||||||
|
|
||||||
|
### 2.4 克隆版本库(clone)
|
||||||
|
|
||||||
|
克隆版本库是将开源项目的版本库完整的克隆到本地的过程。其中包括了版本库的所有提交记录。步骤如下:
|
||||||
|
|
||||||
|
1. 确定需要克隆的版本库地址:从项目的版本库页面中即可找到该地址
|
||||||
|
|
||||||
|
2. 在本地的git命令行执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.osredm.com/xxx/yyy.git
|
||||||
|
```
|
||||||
|
|
||||||
|
其中“https:// git.osredm.com /xxx/yyy.git”是版本库的地址,xxx为用户ID,yyy为项目名称
|
||||||
|
|
||||||
|
3. 如果项目是私有的,根据提示输入版本库用户名和密码,输入当前用户的红山开源平台登录名和密码即可
|
||||||
|
|
||||||
|
注意:如果项目公开, 无需输入口令, 可以直接克隆。 对于私有项目,只有项目成员才具有克隆的权限。
|
||||||
|
|
||||||
|
### 2.5 新建分支、切换分支
|
||||||
|
|
||||||
|
+ 新建分支
|
||||||
|
|
||||||
|
新建分支是指在本地库创建一个新的分支(用于开发新的功能),并且将其同步到远程库。主要步骤如下:
|
||||||
|
|
||||||
|
1. 从已有的分支创建新的分支(如从master分支),例如创建一个dev分支: `git checkout -b dev`
|
||||||
|
|
||||||
|
2. 创建后可以查看一下当前分支,确认当前分支已经切换到dev: `git branch dev master`
|
||||||
|
|
||||||
|
3. 提交该新的分支到远程仓库: `git push origin dev:devl`
|
||||||
|
|
||||||
|
其中: dev为本地新建分支:devl为远程分支,如果devl不存在则会自动创建分支。这里,dev应该等于devl。
|
||||||
|
|
||||||
|
+ 切换分支
|
||||||
|
|
||||||
|
切换分支是指将当前工作分支换为另一个分支 。假设,本地仓库有master和dev两个分支,当前分支是master(其实也可以是其他分支)。那么切换到dev分支的命令是: `git checkout dev`
|
||||||
|
|
||||||
|
注意:用户可以使用git branch命令确认当的分支是否已经切换到dev
|
||||||
|
|
||||||
|
### 2.6 提交代码(commit)
|
||||||
|
|
||||||
|
项目成员在本地编辑代码或修改文件后,可以将新修改的文件提交到本地库:
|
||||||
|
|
||||||
|
1. 将新修改的所有文件添加到本地版本库的暂存区(stage): `git add .`
|
||||||
|
|
||||||
|
注意:如果仅添加单个文件,或一类文件,可以: `git add somefile.txt #添加单个文件`
|
||||||
|
|
||||||
|
2. 将提交到暂存区的修改提交到本地的当前分支: `git commit -m “myfirstcommit”`
|
||||||
|
|
||||||
|
其中,“mycommit”中的内容是关于本次提交的说明文字。
|
||||||
|
|
||||||
|
注意:commit只能将修改的文件提交到本地库,与远程库没有关系。
|
||||||
|
|
||||||
|
### 2.7 推送代码(push)
|
||||||
|
|
||||||
|
项目成员可以将本地提交后的改动,推送到远程库。
|
||||||
|
|
||||||
|
假设用户需要将本地库的dev分支推送至远程库的dev分支,执行: `git push -u origin dev `
|
||||||
|
|
||||||
|
如果用户的当前的本地分支己经是dev, 那么执行: `git push`
|
||||||
|
|
||||||
|
如果用户需要将本地的全部分支推送到远程库。那么执行: `git push -all origin`
|
||||||
|
|
||||||
|
注意: push代码时会提示输入用户密码,请输入红山开源平台登录名和密码即可。 Push代码之前通常要先pull,解决冲突后才能提交,否则不是最新的文件就提交不上去。
|
||||||
|
|
||||||
|
### 2.8 下拉代码(pull)
|
||||||
|
|
||||||
|
下拉代码是指从远程版本库获取代码文件到本地分支。
|
||||||
|
|
||||||
|
例如,用户希望将远程版本库的devl分支下拉到本地的dev分支,需要执行: `git pull origin dev devl`
|
||||||
|
|
||||||
|
注意:下拉代码时可能会出现冲突(即两个分支对同一个文件的同一行代码做了不同的修改)。此时常利用merge来解决冲突。
|
||||||
|
|
||||||
|
### 2.9 合并分支(merge)
|
||||||
|
|
||||||
|
合并分支是指将一个分支合并到当前分支。通常有两种情况:
|
||||||
|
|
||||||
|
1. 将一个本地分支合并到当前分支:
|
||||||
|
|
||||||
|
例如,假设用户希望将本地库的devl分支合并到当前分支dev ,命令如下: `git merge dev1`
|
||||||
|
|
||||||
|
2. 将一个远程库的分支合并到当前分支:
|
||||||
|
|
||||||
|
例如,假设用户希望将远程库的devl分支合并到当前分支dev,有多种方法,这里仅给出最基本的:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout -b temp #新建一个临时分支temp
|
||||||
|
git pull origin dev1:temp #将远程devl分支下拉到temp分支
|
||||||
|
git checkout dev #切换到本地dev分支
|
||||||
|
git merge temp #合并分支(可能 产生冲突,合并完成后,应删除temp分支)
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:合并分支可能会出现冲突(即两个分支对同一个文件的同一行代码做了不同的修改)。
|
||||||
|
|
||||||
|
### 2.10 解决冲突
|
||||||
|
|
||||||
|
冲突是两次不同的提交修改了同一行代码导致的,通常表现为两个分支对同一行代码做了不同的修改。 版本冲突主要出现在以下两种情况:
|
||||||
|
|
||||||
|
第一种情况:在对远程版本库进行pull操作时。
|
||||||
|
|
||||||
|
第二种情况:对本地版本库的不同分支进行merge操作时。
|
||||||
|
|
||||||
|
解决冲突的主要方法有两种:
|
||||||
|
|
||||||
|
1. 对于简单的冲突,直接修改有冲突的文件,然后重新提交即可
|
||||||
|
2. 对于复杂的冲突,需要用**git merge tool**来解决。 复杂的冲突解决方法(基于git merge tool)将在近期提供给大家
|
||||||
|
|
||||||
|
### 2.11 常见错误
|
||||||
|
|
||||||
|
新手在使用Git时经常遇到各种错误,由于平台集成的是标准Git服务(Gitlab),建议大家可以直接在互联网搜索疑难问题的解决办法。 或参考Git使用手册: https://git-scm.com/book/zh/v2 为给大家提供方便,这里先列出一种最常见的错误:
|
||||||
|
|
||||||
|
错误1:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fatal:The remote end hung up unexpectedly
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Windows环境解决方法,在.git/config文件中加入: `[http] postBuffer = 524288000`
|
||||||
|
|
||||||
|
Linux环境解决方法,在命令行执行: `git config http.postBuffer 524288000`
|
||||||
|
|
||||||
|
注:后续我们将列出更多的错误解决办法。
|
||||||
|
|
||||||
|
## 3. 致谢
|
||||||
|
|
||||||
|
红山开源平台的不断发展主要归功于平台的用户页献者群体。他们不仅是使用者,也是设计者、体验者和测试者,他们为平台献策献力,极大拓展了开发团队的视野、提高了开发团队的效率。可以说,没有他们的页献就没有大家看到的红山开源社区。
|
||||||
|
|
||||||
|
如有疏漏请指正,我们将及时更新。
|
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="stylesheet" href="./static/css/theme.css">
|
||||||
|
<link rel="shortcut icon" href="./static/img/1na.png">
|
||||||
|
<title>红山开源社区</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav>
|
||||||
|
<a href="https://forge.osredm.com/projects">返回主站</a>
|
||||||
|
</nav>
|
||||||
|
<div id="app">加载中....</div>
|
||||||
|
<script>
|
||||||
|
if (typeof navigator.serviceWorker !== 'undefined') {
|
||||||
|
navigator.serviceWorker.register('sw.js')
|
||||||
|
}
|
||||||
|
window.$docsify = {
|
||||||
|
//...
|
||||||
|
relativePath: true,
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script src="./static/js/index.js"></script>
|
||||||
|
<script src="./static/js/bash.js"></script>
|
||||||
|
<script src="./static/js/zomm_img.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,858 @@
|
||||||
|
@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600");
|
||||||
|
* {
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||||
|
-webkit-text-size-adjust: none;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
body:not(.ready) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
body:not(.ready) [data-cloak],
|
||||||
|
body:not(.ready) .app-nav,
|
||||||
|
body:not(.ready) > nav {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
div#app {
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: lighter;
|
||||||
|
margin: 40vh auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
div#app:empty::before {
|
||||||
|
content: 'Loading...';
|
||||||
|
}
|
||||||
|
.emoji {
|
||||||
|
height: 1.2rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.progress {
|
||||||
|
background-color: var(--theme-color, #5091ff);
|
||||||
|
height: 2px;
|
||||||
|
left: 0px;
|
||||||
|
position: fixed;
|
||||||
|
right: 0px;
|
||||||
|
top: 0px;
|
||||||
|
transition: width 0.2s, opacity 0.4s;
|
||||||
|
width: 0%;
|
||||||
|
z-index: 999999;
|
||||||
|
}
|
||||||
|
.search a:hover {
|
||||||
|
color: var(--theme-color, #5091ff);
|
||||||
|
}
|
||||||
|
.search .search-keyword {
|
||||||
|
color: var(--theme-color, #5091ff);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
color: #34495e;
|
||||||
|
font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
font-size: 15px;
|
||||||
|
letter-spacing: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
a[disabled] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
kbd {
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
border-radius: 3px;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 12px !important;
|
||||||
|
line-height: 12px;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
padding: 3px 5px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
li input[type='checkbox'] {
|
||||||
|
margin: 0 0.2em 0.25em 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.app-nav {
|
||||||
|
margin: 25px 60px 0 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
text-align: right;
|
||||||
|
z-index: 10;
|
||||||
|
/* navbar dropdown */
|
||||||
|
}
|
||||||
|
.app-nav.no-badge {
|
||||||
|
margin-right: 25px;
|
||||||
|
}
|
||||||
|
.app-nav p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.app-nav > a {
|
||||||
|
margin: 0 1rem;
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
.app-nav ul,
|
||||||
|
.app-nav li {
|
||||||
|
display: inline-block;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.app-nav a {
|
||||||
|
color: inherit;
|
||||||
|
font-size: 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.3s;
|
||||||
|
}
|
||||||
|
.app-nav a:hover {
|
||||||
|
color: var(--theme-color, #5091ff);
|
||||||
|
}
|
||||||
|
.app-nav a.active {
|
||||||
|
border-bottom: 2px solid var(--theme-color, #5091ff);
|
||||||
|
color: var(--theme-color, #5091ff);
|
||||||
|
}
|
||||||
|
.app-nav li {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 1rem;
|
||||||
|
padding: 5px 0;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.app-nav li ul {
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-bottom-color: #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: none;
|
||||||
|
max-height: calc(100vh - 61px);
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 10px 0;
|
||||||
|
position: absolute;
|
||||||
|
right: -15px;
|
||||||
|
text-align: left;
|
||||||
|
top: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.app-nav li ul li {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1rem;
|
||||||
|
margin: 0;
|
||||||
|
margin: 8px 14px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.app-nav li ul a {
|
||||||
|
display: block;
|
||||||
|
font-size: inherit;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.app-nav li ul a.active {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
.app-nav li:hover ul {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.github-corner {
|
||||||
|
border-bottom: 0;
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.github-corner:hover .octo-arm {
|
||||||
|
-webkit-animation: octocat-wave 560ms ease-in-out;
|
||||||
|
animation: octocat-wave 560ms ease-in-out;
|
||||||
|
}
|
||||||
|
.github-corner svg {
|
||||||
|
color: #fff;
|
||||||
|
fill: var(--theme-color, #5091ff);
|
||||||
|
height: 80px;
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
main.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.anchor {
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
.anchor span {
|
||||||
|
color: #34495e;
|
||||||
|
}
|
||||||
|
.anchor:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.sidebar {
|
||||||
|
border-right: 1px solid rgba(0,0,0,0.07);
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 40px 0 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
transition: transform 250ms ease-out;
|
||||||
|
width: 300px;
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
.sidebar > h1 {
|
||||||
|
margin: 0 auto 1rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 300;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.sidebar > h1 a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.sidebar > h1 .app-nav {
|
||||||
|
display: block;
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
.sidebar .sidebar-nav {
|
||||||
|
line-height: 2em;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
}
|
||||||
|
.sidebar li.collapse .app-sub-sidebar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.sidebar ul {
|
||||||
|
margin: 0 0 0 15px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.sidebar li > p {
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.sidebar ul,
|
||||||
|
.sidebar ul li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.sidebar ul li a {
|
||||||
|
border-bottom: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.sidebar ul li ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
.sidebar::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
.sidebar::-webkit-scrollbar-thumb {
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.sidebar:hover::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(136,136,136,0.4);
|
||||||
|
}
|
||||||
|
.sidebar:hover::-webkit-scrollbar-track {
|
||||||
|
background: rgba(136,136,136,0.1);
|
||||||
|
}
|
||||||
|
.sidebar-toggle {
|
||||||
|
background-color: transparent;
|
||||||
|
background-color: rgba(255,255,255,0.8);
|
||||||
|
border: 0;
|
||||||
|
outline: none;
|
||||||
|
padding: 10px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
text-align: center;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
width: 284px;
|
||||||
|
z-index: 30;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.sidebar-toggle:hover .sidebar-toggle-button {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
.sidebar-toggle span {
|
||||||
|
background-color: var(--theme-color, #5091ff);
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
width: 16px;
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
body.sticky .sidebar,
|
||||||
|
body.sticky .sidebar-toggle {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding-top: 60px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 300px;
|
||||||
|
transition: left 250ms ease;
|
||||||
|
}
|
||||||
|
.markdown-section {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 80%;
|
||||||
|
padding: 30px 15px 40px 15px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.markdown-section > * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: inherit;
|
||||||
|
}
|
||||||
|
.markdown-section > :first-child {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
.markdown-section hr {
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
margin: 2em 0;
|
||||||
|
}
|
||||||
|
.markdown-section iframe {
|
||||||
|
border: 1px solid #eee;
|
||||||
|
/* fix horizontal overflow on iOS Safari */
|
||||||
|
width: 1px;
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
.markdown-section table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
overflow: auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.markdown-section th {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 6px 13px;
|
||||||
|
}
|
||||||
|
.markdown-section td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 6px 13px;
|
||||||
|
}
|
||||||
|
.markdown-section tr {
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
.markdown-section tr:nth-child(2n) {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
.markdown-section p.tip {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
border-bottom-right-radius: 2px;
|
||||||
|
border-left: 4px solid #f66;
|
||||||
|
border-top-right-radius: 2px;
|
||||||
|
margin: 2em 0;
|
||||||
|
padding: 12px 24px 12px 30px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.markdown-section p.tip:before {
|
||||||
|
background-color: #f66;
|
||||||
|
border-radius: 100%;
|
||||||
|
color: #fff;
|
||||||
|
content: '!';
|
||||||
|
font-family: 'Dosis', 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
left: -12px;
|
||||||
|
line-height: 20px;
|
||||||
|
position: absolute;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
text-align: center;
|
||||||
|
top: 14px;
|
||||||
|
}
|
||||||
|
.markdown-section p.tip code {
|
||||||
|
background-color: #efefef;
|
||||||
|
}
|
||||||
|
.markdown-section p.tip em {
|
||||||
|
color: #34495e;
|
||||||
|
}
|
||||||
|
.markdown-section p.warn {
|
||||||
|
background: rgba(66,185,131,0.1);
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
.markdown-section ul.task-list > li {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
body.close .sidebar {
|
||||||
|
transform: translateX(-300px);
|
||||||
|
}
|
||||||
|
body.close .sidebar-toggle {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
body.close .content {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
@media print {
|
||||||
|
.github-corner,
|
||||||
|
.sidebar-toggle,
|
||||||
|
.sidebar,
|
||||||
|
.app-nav {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.github-corner,
|
||||||
|
.sidebar-toggle,
|
||||||
|
.sidebar {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
.app-nav {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
.app-nav li ul {
|
||||||
|
top: 30px;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
height: auto;
|
||||||
|
min-height: 100vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
.sidebar {
|
||||||
|
left: -300px;
|
||||||
|
transition: transform 250ms ease-out;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
left: 0;
|
||||||
|
max-width: 100vw;
|
||||||
|
position: static;
|
||||||
|
padding-top: 20px;
|
||||||
|
transition: transform 250ms ease;
|
||||||
|
}
|
||||||
|
.app-nav,
|
||||||
|
.github-corner {
|
||||||
|
transition: transform 250ms ease-out;
|
||||||
|
}
|
||||||
|
.sidebar-toggle {
|
||||||
|
background-color: transparent;
|
||||||
|
width: auto;
|
||||||
|
padding: 30px 30px 10px 10px;
|
||||||
|
}
|
||||||
|
body.close .sidebar {
|
||||||
|
transform: translateX(300px);
|
||||||
|
}
|
||||||
|
body.close .sidebar-toggle {
|
||||||
|
background-color: rgba(255,255,255,0.8);
|
||||||
|
transition: 1s background-color;
|
||||||
|
width: 284px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
body.close .content {
|
||||||
|
transform: translateX(300px);
|
||||||
|
}
|
||||||
|
body.close .app-nav,
|
||||||
|
body.close .github-corner {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.github-corner:hover .octo-arm {
|
||||||
|
-webkit-animation: none;
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
.github-corner .octo-arm {
|
||||||
|
-webkit-animation: octocat-wave 560ms ease-in-out;
|
||||||
|
animation: octocat-wave 560ms ease-in-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes octocat-wave {
|
||||||
|
0%, 100% {
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
20%, 60% {
|
||||||
|
transform: rotate(-25deg);
|
||||||
|
}
|
||||||
|
40%, 80% {
|
||||||
|
transform: rotate(10deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes octocat-wave {
|
||||||
|
0%, 100% {
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
20%, 60% {
|
||||||
|
transform: rotate(-25deg);
|
||||||
|
}
|
||||||
|
40%, 80% {
|
||||||
|
transform: rotate(10deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
section.cover {
|
||||||
|
align-items: center;
|
||||||
|
background-position: center center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
section.cover.show {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
section.cover.has-mask .mask {
|
||||||
|
background-color: #fff;
|
||||||
|
opacity: 0.8;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
section.cover .cover-main {
|
||||||
|
flex: 1;
|
||||||
|
margin: -20px 16px 0;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
section.cover a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
section.cover a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
section.cover p {
|
||||||
|
line-height: 1.5rem;
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
section.cover h1 {
|
||||||
|
color: inherit;
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: 300;
|
||||||
|
margin: 0.625rem 0 2.5rem;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
section.cover h1 a {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
section.cover h1 small {
|
||||||
|
bottom: -0.4375rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
section.cover blockquote {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
section.cover ul {
|
||||||
|
line-height: 1.8;
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 1em auto;
|
||||||
|
max-width: 500px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
section.cover .cover-main > p:last-child a {
|
||||||
|
border-color: var(--theme-color, #5091ff);
|
||||||
|
border-radius: 2rem;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: var(--theme-color, #5091ff);
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 1.05rem;
|
||||||
|
letter-spacing: 0.1rem;
|
||||||
|
margin: 0.5rem 1rem;
|
||||||
|
padding: 0.75em 2rem;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
section.cover .cover-main > p:last-child a:last-child {
|
||||||
|
background-color: var(--theme-color, #5091ff);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
section.cover .cover-main > p:last-child a:last-child:hover {
|
||||||
|
color: inherit;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
section.cover .cover-main > p:last-child a:hover {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
section.cover blockquote > p > a {
|
||||||
|
border-bottom: 2px solid var(--theme-color, #5091ff);
|
||||||
|
transition: color 0.3s;
|
||||||
|
}
|
||||||
|
section.cover blockquote > p > a:hover {
|
||||||
|
color: var(--theme-color, #5091ff);
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
/* sidebar */
|
||||||
|
.sidebar {
|
||||||
|
background-color: #fff;
|
||||||
|
color: #364149;
|
||||||
|
}
|
||||||
|
.sidebar li {
|
||||||
|
margin: 6px 0 6px 0;
|
||||||
|
}
|
||||||
|
.sidebar ul li a {
|
||||||
|
color: #505d6b;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
overflow: hidden;
|
||||||
|
text-decoration: none;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.sidebar ul li a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.sidebar ul li ul {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.sidebar ul li.active > a {
|
||||||
|
border-right: 2px solid;
|
||||||
|
color: var(--theme-color, #5091ff);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.app-sub-sidebar li::before {
|
||||||
|
content: '-';
|
||||||
|
padding-right: 4px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
/* markdown content found on pages */
|
||||||
|
.markdown-section h1,
|
||||||
|
.markdown-section h2,
|
||||||
|
.markdown-section h3,
|
||||||
|
.markdown-section h4,
|
||||||
|
.markdown-section strong {
|
||||||
|
color: #2c3e50;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.markdown-section a {
|
||||||
|
color: var(--theme-color, #5091ff);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.markdown-section h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin: 0 0 1rem;
|
||||||
|
}
|
||||||
|
.markdown-section h2 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
margin: 45px 0 0.8rem;
|
||||||
|
}
|
||||||
|
.markdown-section h3 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin: 40px 0 0.6rem;
|
||||||
|
}
|
||||||
|
.markdown-section h4 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
.markdown-section h5 {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
.markdown-section h6 {
|
||||||
|
color: #777;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
.markdown-section figure,
|
||||||
|
.markdown-section p {
|
||||||
|
margin: 1.2em 0;
|
||||||
|
}
|
||||||
|
.markdown-section p,
|
||||||
|
.markdown-section ul,
|
||||||
|
.markdown-section ol {
|
||||||
|
line-height: 1.6rem;
|
||||||
|
word-spacing: 0.05rem;
|
||||||
|
}
|
||||||
|
.markdown-section ul,
|
||||||
|
.markdown-section ol {
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
.markdown-section blockquote {
|
||||||
|
border-left: 4px solid var(--theme-color, #5091ff);
|
||||||
|
color: #858585;
|
||||||
|
margin: 2em 0;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
.markdown-section blockquote p {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.markdown-section iframe {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
.markdown-section em {
|
||||||
|
color: #7f8c8d;
|
||||||
|
}
|
||||||
|
.markdown-section code,
|
||||||
|
.markdown-section pre,
|
||||||
|
.markdown-section output::after {
|
||||||
|
font-family: 'Roboto Mono', Monaco, courier, monospace;
|
||||||
|
}
|
||||||
|
.markdown-section code,
|
||||||
|
.markdown-section pre {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
.markdown-section pre,
|
||||||
|
.markdown-section output {
|
||||||
|
margin: 1.2em 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.markdown-section pre > code,
|
||||||
|
.markdown-section output {
|
||||||
|
border-radius: 2px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.markdown-section pre > code,
|
||||||
|
.markdown-section output::after {
|
||||||
|
-moz-osx-font-smoothing: initial;
|
||||||
|
-webkit-font-smoothing: initial;
|
||||||
|
}
|
||||||
|
.markdown-section code {
|
||||||
|
border-radius: 2px;
|
||||||
|
color: #e96900;
|
||||||
|
margin: 0 2px;
|
||||||
|
padding: 3px 5px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
.markdown-section > :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) code {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
.markdown-section pre {
|
||||||
|
padding: 0 1.4rem;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
overflow: auto;
|
||||||
|
word-wrap: normal;
|
||||||
|
}
|
||||||
|
.markdown-section pre > code {
|
||||||
|
color: #525252;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 2.2em 5px;
|
||||||
|
line-height: inherit;
|
||||||
|
margin: 0 2px;
|
||||||
|
max-width: inherit;
|
||||||
|
overflow: inherit;
|
||||||
|
white-space: inherit;
|
||||||
|
}
|
||||||
|
.markdown-section output {
|
||||||
|
padding: 1.7rem 1.4rem;
|
||||||
|
border: 1px dotted #ccc;
|
||||||
|
}
|
||||||
|
.markdown-section output > :first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.markdown-section output > :last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.markdown-section code::after,
|
||||||
|
.markdown-section code::before,
|
||||||
|
.markdown-section output::after,
|
||||||
|
.markdown-section output::before {
|
||||||
|
letter-spacing: 0.05rem;
|
||||||
|
}
|
||||||
|
.markdown-section pre::after,
|
||||||
|
.markdown-section output::after {
|
||||||
|
color: #ccc;
|
||||||
|
font-size: 0.6rem;
|
||||||
|
font-weight: 600;
|
||||||
|
height: 15px;
|
||||||
|
line-height: 15px;
|
||||||
|
padding: 5px 10px 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
text-align: right;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.markdown-section pre::after,
|
||||||
|
.markdown-section output::after {
|
||||||
|
content: attr(data-lang);
|
||||||
|
}
|
||||||
|
/* code highlight */
|
||||||
|
.token.comment,
|
||||||
|
.token.prolog,
|
||||||
|
.token.doctype,
|
||||||
|
.token.cdata {
|
||||||
|
color: #8e908c;
|
||||||
|
}
|
||||||
|
.token.namespace {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
.token.boolean,
|
||||||
|
.token.number {
|
||||||
|
color: #c76b29;
|
||||||
|
}
|
||||||
|
.token.punctuation {
|
||||||
|
color: #525252;
|
||||||
|
}
|
||||||
|
.token.property {
|
||||||
|
color: #c08b30;
|
||||||
|
}
|
||||||
|
.token.tag {
|
||||||
|
color: #2973b7;
|
||||||
|
}
|
||||||
|
.token.string {
|
||||||
|
color: var(--theme-color, #5091ff);
|
||||||
|
}
|
||||||
|
.token.selector {
|
||||||
|
color: #6679cc;
|
||||||
|
}
|
||||||
|
.token.attr-name {
|
||||||
|
color: #2973b7;
|
||||||
|
}
|
||||||
|
.token.entity,
|
||||||
|
.token.url,
|
||||||
|
.language-css .token.string,
|
||||||
|
.style .token.string {
|
||||||
|
color: #22a2c9;
|
||||||
|
}
|
||||||
|
.token.attr-value,
|
||||||
|
.token.control,
|
||||||
|
.token.directive,
|
||||||
|
.token.unit {
|
||||||
|
color: var(--theme-color, #5091ff);
|
||||||
|
}
|
||||||
|
.token.keyword,
|
||||||
|
.token.function {
|
||||||
|
color: #e96900;
|
||||||
|
}
|
||||||
|
.token.statement,
|
||||||
|
.token.regex,
|
||||||
|
.token.atrule {
|
||||||
|
color: #22a2c9;
|
||||||
|
}
|
||||||
|
.token.placeholder,
|
||||||
|
.token.variable {
|
||||||
|
color: #3d8fd1;
|
||||||
|
}
|
||||||
|
.token.deleted {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
.token.inserted {
|
||||||
|
border-bottom: 1px dotted #202746;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.token.italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.token.important,
|
||||||
|
.token.bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.token.important {
|
||||||
|
color: #c94922;
|
||||||
|
}
|
||||||
|
.token.entity {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
code .token {
|
||||||
|
-moz-osx-font-smoothing: initial;
|
||||||
|
-webkit-font-smoothing: initial;
|
||||||
|
min-height: 1.5rem;
|
||||||
|
position: relative;
|
||||||
|
left: auto;
|
||||||
|
}
|
After Width: | Height: | Size: 9.7 KiB |
After Width: | Height: | Size: 529 KiB |
After Width: | Height: | Size: 242 KiB |
After Width: | Height: | Size: 530 KiB |
After Width: | Height: | Size: 212 KiB |
After Width: | Height: | Size: 295 KiB |
After Width: | Height: | Size: 301 KiB |
After Width: | Height: | Size: 294 KiB |
After Width: | Height: | Size: 274 KiB |
After Width: | Height: | Size: 326 KiB |
After Width: | Height: | Size: 333 KiB |
After Width: | Height: | Size: 290 KiB |
After Width: | Height: | Size: 287 KiB |
After Width: | Height: | Size: 285 KiB |
After Width: | Height: | Size: 289 KiB |
After Width: | Height: | Size: 300 KiB |
After Width: | Height: | Size: 294 KiB |
After Width: | Height: | Size: 322 KiB |
After Width: | Height: | Size: 311 KiB |
After Width: | Height: | Size: 328 KiB |
After Width: | Height: | Size: 266 KiB |
After Width: | Height: | Size: 306 KiB |
After Width: | Height: | Size: 256 KiB |
After Width: | Height: | Size: 332 KiB |
After Width: | Height: | Size: 322 KiB |
After Width: | Height: | Size: 527 KiB |
After Width: | Height: | Size: 256 KiB |
|
@ -0,0 +1,227 @@
|
||||||
|
(function (Prism) {
|
||||||
|
// $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|'
|
||||||
|
// + LC_ALL, RANDOM, REPLY, SECONDS.
|
||||||
|
// + make sure PS1..4 are here as they are not always set,
|
||||||
|
// - some useless things.
|
||||||
|
var envVars = '\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b';
|
||||||
|
|
||||||
|
var commandAfterHeredoc = {
|
||||||
|
pattern: /(^(["']?)\w+\2)[ \t]+\S.*/,
|
||||||
|
lookbehind: true,
|
||||||
|
alias: 'punctuation', // this looks reasonably well in all themes
|
||||||
|
inside: null // see below
|
||||||
|
};
|
||||||
|
|
||||||
|
var insideString = {
|
||||||
|
'bash': commandAfterHeredoc,
|
||||||
|
'environment': {
|
||||||
|
pattern: RegExp('\\$' + envVars),
|
||||||
|
alias: 'constant'
|
||||||
|
},
|
||||||
|
'variable': [
|
||||||
|
// [0]: Arithmetic Environment
|
||||||
|
{
|
||||||
|
pattern: /\$?\(\([\s\S]+?\)\)/,
|
||||||
|
greedy: true,
|
||||||
|
inside: {
|
||||||
|
// If there is a $ sign at the beginning highlight $(( and )) as variable
|
||||||
|
'variable': [
|
||||||
|
{
|
||||||
|
pattern: /(^\$\(\([\s\S]+)\)\)/,
|
||||||
|
lookbehind: true
|
||||||
|
},
|
||||||
|
/^\$\(\(/
|
||||||
|
],
|
||||||
|
'number': /\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,
|
||||||
|
// Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic
|
||||||
|
'operator': /--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,
|
||||||
|
// If there is no $ sign at the beginning highlight (( and )) as punctuation
|
||||||
|
'punctuation': /\(\(?|\)\)?|,|;/
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// [1]: Command Substitution
|
||||||
|
{
|
||||||
|
pattern: /\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,
|
||||||
|
greedy: true,
|
||||||
|
inside: {
|
||||||
|
'variable': /^\$\(|^`|\)$|`$/
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// [2]: Brace expansion
|
||||||
|
{
|
||||||
|
pattern: /\$\{[^}]+\}/,
|
||||||
|
greedy: true,
|
||||||
|
inside: {
|
||||||
|
'operator': /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,
|
||||||
|
'punctuation': /[\[\]]/,
|
||||||
|
'environment': {
|
||||||
|
pattern: RegExp('(\\{)' + envVars),
|
||||||
|
lookbehind: true,
|
||||||
|
alias: 'constant'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/\$(?:\w+|[#?*!@$])/
|
||||||
|
],
|
||||||
|
// Escape sequences from echo and printf's manuals, and escaped quotes.
|
||||||
|
'entity': /\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/
|
||||||
|
};
|
||||||
|
|
||||||
|
Prism.languages.bash = {
|
||||||
|
'shebang': {
|
||||||
|
pattern: /^#!\s*\/.*/,
|
||||||
|
alias: 'important'
|
||||||
|
},
|
||||||
|
'comment': {
|
||||||
|
pattern: /(^|[^"{\\$])#.*/,
|
||||||
|
lookbehind: true
|
||||||
|
},
|
||||||
|
'function-name': [
|
||||||
|
// a) function foo {
|
||||||
|
// b) foo() {
|
||||||
|
// c) function foo() {
|
||||||
|
// but not “foo {”
|
||||||
|
{
|
||||||
|
// a) and c)
|
||||||
|
pattern: /(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,
|
||||||
|
lookbehind: true,
|
||||||
|
alias: 'function'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// b)
|
||||||
|
pattern: /\b[\w-]+(?=\s*\(\s*\)\s*\{)/,
|
||||||
|
alias: 'function'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
// Highlight variable names as variables in for and select beginnings.
|
||||||
|
'for-or-select': {
|
||||||
|
pattern: /(\b(?:for|select)\s+)\w+(?=\s+in\s)/,
|
||||||
|
alias: 'variable',
|
||||||
|
lookbehind: true
|
||||||
|
},
|
||||||
|
// Highlight variable names as variables in the left-hand part
|
||||||
|
// of assignments (“=” and “+=”).
|
||||||
|
'assign-left': {
|
||||||
|
pattern: /(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,
|
||||||
|
inside: {
|
||||||
|
'environment': {
|
||||||
|
pattern: RegExp('(^|[\\s;|&]|[<>]\\()' + envVars),
|
||||||
|
lookbehind: true,
|
||||||
|
alias: 'constant'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
alias: 'variable',
|
||||||
|
lookbehind: true
|
||||||
|
},
|
||||||
|
'string': [
|
||||||
|
// Support for Here-documents https://en.wikipedia.org/wiki/Here_document
|
||||||
|
{
|
||||||
|
pattern: /((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,
|
||||||
|
lookbehind: true,
|
||||||
|
greedy: true,
|
||||||
|
inside: insideString
|
||||||
|
},
|
||||||
|
// Here-document with quotes around the tag
|
||||||
|
// → No expansion (so no “inside”).
|
||||||
|
{
|
||||||
|
pattern: /((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,
|
||||||
|
lookbehind: true,
|
||||||
|
greedy: true,
|
||||||
|
inside: {
|
||||||
|
'bash': commandAfterHeredoc
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// “Normal” string
|
||||||
|
{
|
||||||
|
// https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
|
||||||
|
pattern: /(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,
|
||||||
|
lookbehind: true,
|
||||||
|
greedy: true,
|
||||||
|
inside: insideString
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html
|
||||||
|
pattern: /(^|[^$\\])'[^']*'/,
|
||||||
|
lookbehind: true,
|
||||||
|
greedy: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html
|
||||||
|
pattern: /\$'(?:[^'\\]|\\[\s\S])*'/,
|
||||||
|
greedy: true,
|
||||||
|
inside: {
|
||||||
|
'entity': insideString.entity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'environment': {
|
||||||
|
pattern: RegExp('\\$?' + envVars),
|
||||||
|
alias: 'constant'
|
||||||
|
},
|
||||||
|
'variable': insideString.variable,
|
||||||
|
'function': {
|
||||||
|
pattern: /(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,
|
||||||
|
lookbehind: true
|
||||||
|
},
|
||||||
|
'keyword': {
|
||||||
|
pattern: /(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,
|
||||||
|
lookbehind: true
|
||||||
|
},
|
||||||
|
// https://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html
|
||||||
|
'builtin': {
|
||||||
|
pattern: /(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,
|
||||||
|
lookbehind: true,
|
||||||
|
// Alias added to make those easier to distinguish from strings.
|
||||||
|
alias: 'class-name'
|
||||||
|
},
|
||||||
|
'boolean': {
|
||||||
|
pattern: /(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,
|
||||||
|
lookbehind: true
|
||||||
|
},
|
||||||
|
'file-descriptor': {
|
||||||
|
pattern: /\B&\d\b/,
|
||||||
|
alias: 'important'
|
||||||
|
},
|
||||||
|
'operator': {
|
||||||
|
// Lots of redirections here, but not just that.
|
||||||
|
pattern: /\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,
|
||||||
|
inside: {
|
||||||
|
'file-descriptor': {
|
||||||
|
pattern: /^\d/,
|
||||||
|
alias: 'important'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'punctuation': /\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,
|
||||||
|
'number': {
|
||||||
|
pattern: /(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,
|
||||||
|
lookbehind: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
commandAfterHeredoc.inside = Prism.languages.bash;
|
||||||
|
|
||||||
|
/* Patterns in command substitution. */
|
||||||
|
var toBeCopied = [
|
||||||
|
'comment',
|
||||||
|
'function-name',
|
||||||
|
'for-or-select',
|
||||||
|
'assign-left',
|
||||||
|
'string',
|
||||||
|
'environment',
|
||||||
|
'function',
|
||||||
|
'keyword',
|
||||||
|
'builtin',
|
||||||
|
'boolean',
|
||||||
|
'file-descriptor',
|
||||||
|
'operator',
|
||||||
|
'punctuation',
|
||||||
|
'number'
|
||||||
|
];
|
||||||
|
var inside = insideString.variable[1].inside;
|
||||||
|
for (var i = 0; i < toBeCopied.length; i++) {
|
||||||
|
inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
Prism.languages.shell = Prism.languages.bash;
|
||||||
|
}(Prism));
|
|
@ -0,0 +1,83 @@
|
||||||
|
/* ===========================================================
|
||||||
|
* docsify sw.js
|
||||||
|
* ===========================================================
|
||||||
|
* Copyright 2016 @huxpro
|
||||||
|
* Licensed under Apache 2.0
|
||||||
|
* Register service worker.
|
||||||
|
* ========================================================== */
|
||||||
|
|
||||||
|
const RUNTIME = 'docsify'
|
||||||
|
const HOSTNAME_WHITELIST = [
|
||||||
|
self.location.hostname,
|
||||||
|
'fonts.gstatic.com',
|
||||||
|
'fonts.googleapis.com',
|
||||||
|
'cdn.jsdelivr.net'
|
||||||
|
]
|
||||||
|
|
||||||
|
// The Util Function to hack URLs of intercepted requests
|
||||||
|
const getFixedUrl = (req) => {
|
||||||
|
var now = Date.now()
|
||||||
|
var url = new URL(req.url)
|
||||||
|
|
||||||
|
// 1. fixed http URL
|
||||||
|
// Just keep syncing with location.protocol
|
||||||
|
// fetch(httpURL) belongs to active mixed content.
|
||||||
|
// And fetch(httpRequest) is not supported yet.
|
||||||
|
url.protocol = self.location.protocol
|
||||||
|
|
||||||
|
// 2. add query for caching-busting.
|
||||||
|
// Github Pages served with Cache-Control: max-age=600
|
||||||
|
// max-age on mutable content is error-prone, with SW life of bugs can even extend.
|
||||||
|
// Until cache mode of Fetch API landed, we have to workaround cache-busting with query string.
|
||||||
|
// Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190
|
||||||
|
if (url.hostname === self.location.hostname) {
|
||||||
|
url.search += (url.search ? '&' : '?') + 'cache-bust=' + now
|
||||||
|
}
|
||||||
|
return url.href
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Lifecycle Activate
|
||||||
|
* New one activated when old isnt being used.
|
||||||
|
*
|
||||||
|
* waitUntil(): activating ====> activated
|
||||||
|
*/
|
||||||
|
self.addEventListener('activate', event => {
|
||||||
|
event.waitUntil(self.clients.claim())
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Functional Fetch
|
||||||
|
* All network requests are being intercepted here.
|
||||||
|
*
|
||||||
|
* void respondWith(Promise<Response> r)
|
||||||
|
*/
|
||||||
|
self.addEventListener('fetch', event => {
|
||||||
|
// Skip some of cross-origin requests, like those for Google Analytics.
|
||||||
|
if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) {
|
||||||
|
// Stale-while-revalidate
|
||||||
|
// similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale
|
||||||
|
// Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1
|
||||||
|
const cached = caches.match(event.request)
|
||||||
|
const fixedUrl = getFixedUrl(event.request)
|
||||||
|
const fetched = fetch(fixedUrl, { cache: 'no-store' })
|
||||||
|
const fetchedCopy = fetched.then(resp => resp.clone())
|
||||||
|
|
||||||
|
// Call respondWith() with whatever we get first.
|
||||||
|
// If the fetch fails (e.g disconnected), wait for the cache.
|
||||||
|
// If there’s nothing in cache, wait for the fetch.
|
||||||
|
// If neither yields a response, return offline pages.
|
||||||
|
event.respondWith(
|
||||||
|
Promise.race([fetched.catch(_ => cached), cached])
|
||||||
|
.then(resp => resp || fetched)
|
||||||
|
.catch(_ => { /* eat any errors */ })
|
||||||
|
)
|
||||||
|
|
||||||
|
// Update the cache with the version we fetched (only for ok status)
|
||||||
|
event.waitUntil(
|
||||||
|
Promise.all([fetchedCopy, caches.open(RUNTIME)])
|
||||||
|
.then(([response, cache]) => response.ok && cache.put(event.request, response))
|
||||||
|
.catch(_ => { /* eat any errors */ })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|