Compare commits

...

13 Commits

22 changed files with 5565 additions and 89 deletions

View File

@ -20,17 +20,22 @@ Quick Reference
[JavaScript](./docs/javascript.md)<!--rehype:style=background: rgb(203 183 31/var(\-\-bg\-opacity));-->
[JSON](./docs/json.md)<!--rehype:style=background: rgb(57 59 60/var(\-\-bg\-opacity));-->
[React](./docs/react.md)<!--rehype:style=background: rgb(34 143 173/var(\-\-bg\-opacity));-->
[Styled Components](./docs/styled-components.md)<!--rehype:style=background: rgb(221 60 184/var(\-\-bg\-opacity));-->
[TOML](./docs/toml.md)<!--rehype:style=background: rgb(132 132 132/var(\-\-bg\-opacity));-->
[Markdown](./docs/markdown.md)<!--rehype:style=background: rgb(103 61 156/var(\-\-bg\-opacity));-->
[TypeScript](./docs/typescript.md)<!--rehype:style=background: rgb(49 120 198/var(\-\-bg\-opacity));-->
[YAML](./docs/yaml.md)<!--rehype:style=background: rgb(91 163 230/var(\-\-bg\-opacity));-->
<!--rehype:class=home-card-->
## 工具包
[Emmet](./docs/emmet.md)<!--rehype:style=background: rgb(122 203 23/var(\-\-bg\-opacity));-->
[nginx](./docs/nginx.md)<!--rehype:style=background: rgb(0 193 9/var(\-\-bg\-opacity));-->
[npm](./docs/npm.md)<!--rehype:style=background: rgb(203 2 0/var(\-\-bg\-opacity));-->
[package.json](./docs/package.json.md)<!--rehype:style=background: rgb(132 132 132/var(\-\-bg\-opacity));-->
[Semver](./docs/semver.md)<!--rehype:style=background: rgb(106 111 141/var(\-\-bg\-opacity));-->
[Sketch](./docs/sketch.md)<!--rehype:style=background: rgb(223 148 0/var(\-\-bg\-opacity));-->
[Sublime Text](./docs/sublime-text.md)<!--rehype:style=background: rgb(223 148 0/var(\-\-bg\-opacity));-->
[Jest](./docs/jest.md)<!--rehype:style=background: rgb(153 66 91/var(\-\-bg\-opacity));-->
[RegEx](./docs/regex.md)<!--rehype:style=background: rgb(149 36 155/var(\-\-bg\-opacity));-->
[VSCode](./docs/vscode.md)<!--rehype:style=background: rgb(91 163 230/var(\-\-bg\-opacity));-->

View File

@ -25,12 +25,13 @@ $ docker run -d -p 80:80 docker/getting-started
在前台创建并运行容器
```shell
$ docker run -it -p 8001:8080 --name my-nginx nginx
$ docker run -it -p --rm 8001:8080 --name my-nginx nginx
```
----
- `-it` - 交互式 bash 模式
- `--rm` - 容器终止运行后自动删除容器文件
- `-p 8001:8080` - 将 `8001` 端口映射到容器中的 `8080` 端口
- `--name my-nginx` - 指定名称
- `nginx` - 要使用的镜像
@ -291,6 +292,64 @@ $ docker volume ls
$ docker volume prune
```
### Docker Compose
<!--rehype:wrap-class=col-span-2-->
:- | :-
:- | :-
`docker-compose up` | 创建和启动容器
`docker-compose up -d` | 以分离模式创建和启动容器
`docker-compose down` | 停止和删除容器、网络、映像和卷
`docker-compose logs` | 查看容器的输出
`docker-compose restart` | 重启所有服务
`docker-compose pull` | 拉取所有图片服务
`docker-compose build` | 构建所有图像服务
`docker-compose config` | 验证并查看 Compose 文件
`docker-compose scale <service_name>=<replica>` | 规模特殊服务
`docker-compose top` | 显示正在运行的进程
`docker-compose run -rm -p 2022:22 web bash` | 启动 Web 服务并运行 bash 作为其命令,删除旧容器。
### Docker Services
:- | :-
:- | :-
`docker service create <options> <image> <command>` | 创建新服务
`docker service inspect --pretty <service_name>` | 显示详细信息服务
`docker service ls` | 列出服务
`docker service ps` | 列出服务的任务
`docker service scale <service_name>=<replica>` | 规模特殊服务
`docker service update <options> <service_name>` | 更新服务选项
### Docker Stack
:- | :-
:- | :-
`docker stack ls` | 列出此 Docker 主机上所有正在运行的应用程序
`docker stack deploy -c <composefile> <appname>` | 运行指定的 Compose 文件
`docker stack services <appname>` | 列出与应用关联的服务
`docker stack ps <appname>` | 列出与应用关联的正在运行的容器
`docker stack rm <appname>` | 拆掉一个应用程序
### Docker Machine
<!--rehype:wrap-class=col-span-2-->
:- | :-
:- | :-
`docker-machine create --driver virtualbox myvm1` | 创建虚拟机Mac、Win7、Linux
`docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" myvm1` | Win10
`docker-machine env myvm1` | 查看有关您的节点的基本信息
`docker-machine ssh myvm1 "docker node ls"` | 列出集群中的节点
`docker-machine ssh myvm1 "docker node inspect <node ID>"` | 检查节点
`docker-machine ssh myvm1 "docker swarm join-token -q worker"` | 查看加入令牌
`docker-machine ssh myvm1` | 打开与 VM 的 SSH 会话; 输入“exit”结束
`docker-machine ssh myvm2 "docker swarm leave"` | 让工人离开群体
`docker-machine ssh myvm1 "docker swarm leave -f"` | 让主人离开,杀群
`docker-machine start myvm1` | 启动当前未运行的 VM
`docker-machine stop $(docker-machine ls -q)` | 停止所有正在运行的虚拟机
`docker-machine rm $(docker-machine ls -q)` | 删除所有虚拟机及其磁盘映像
`docker-machine scp docker-compose.yml myvm1:~` | 将文件复制到节点的主目录
`docker-machine ssh myvm1 "docker stack deploy -c <file> <app>"` | 部署应用
另见
----

2404
docs/emmet.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -328,25 +328,21 @@ Git 技巧
### 重命名分支
#### **重命名**为`new`
- **重命名**为`new`
```shell
$ git branch -m <new>
$ git branch -m <old> <new> #重命名分支
```
#### **推送**并重置
- **推送**并重置
```shell
$ git push origin -u <new>
```
#### **删除**远程分支
- **删除**远程分支
```shell
$ git push origin --delete <old> #方法1
$ git push origin :oldBranchName #方法2
```
<!--rehype:className=style-timeline-->
### Log

View File

@ -5,8 +5,10 @@ Jest 是一款优雅、简洁的 JavaScript 测试框架。
入门
----
<!--rehype:body-class=cols-6-->
### 介绍
<!--rehype:wrap-class=col-span-2 row-span-2-->
[Jest](https://jestjs.io/) 是一款优雅、简洁的 JavaScript 测试框架。
@ -16,9 +18,54 @@ Jest 是一款优雅、简洁的 JavaScript 测试框架。
- `快照` 轻松编写持续追踪大型对象的测试,并在测试旁或代码内显示实时快照。
- `代码覆盖` 无需其他操作,您仅需添加 `--coverage` 参数来生成代码覆盖率报告。
### 测试结构
### 快速开始
<!--rehype:wrap-class=col-span-2 row-span-2-->
```bash
npm install --save-dev jest
```
Add to `package.json`
```js
"scripts": {
"test": "jest"
}
```
运行你的测试
```bash
npm test -- --watch
```
查看: [Getting started](https://jestjs.io/docs/getting-started)
### 编写测试
<!--rehype:wrap-class=col-span-2-->
```js
describe('My work', () => {
test('works', () => {
expect(2).toEqual(2)
})
})
```
### BDD 语法
<!--rehype:wrap-class=col-span-2-->
```js {2}
describe('My work', () => {
it('works', () => { // `it`是`test`的别名
···
})
})
```
### 测试结构
<!--rehype:wrap-class=col-span-3 row-span-2-->
```js
describe('makePoniesPink', () => {
beforeAll(() => {
@ -40,6 +87,143 @@ describe('makePoniesPink', () => {
})
```
### 聚焦测试
```js
describe.only(···)
it.only(···)
// 别名: fit()
```
查看: [test.only](https://jestjs.io/docs/api#testonlyname-fn-timeout)
### 可选参数
<!--rehype:wrap-class=col-span-2-->
| Flag | Description |
| --------------------- | ---------------------------------------- |
| `--coverage` | 查看测试覆盖率摘要 |
| `--detectOpenHandles` | 查看未关闭端口的摘要 |
| `--runInBand` | 一个接一个地运行所有测试 |
| `--bail,-b` | 失败跳出测试 |
更多参数查看 [Jest CLI Options](https://jestjs.io/docs/next/cli#--bailn)
### 跳过测试
```js
describe.skip(···)
it.skip(···)
// 别名: xit()
```
查看: [test.skip](https://jestjs.io/docs/next/api#testskipname-fn)
### 基本测试用例
<!--rehype:wrap-class=col-span-2-->
```js
expect(value).not.toBe(value)
.toEqual(value)
.toBeTruthy()
// Errors 测试
expect(value).toThrow(error)
.toThrowErrorMatchingSnapshot()
```
### 快照
<!--rehype:wrap-class=col-span-2-->
```js
expect(value)
.toMatchSnapshot()
.toMatchInlineSnapshot()
```
### Errors
<!--rehype:wrap-class=col-span-2-->
```js
expect(value)
.toThrow(error)
.toThrowErrorMatchingSnapshot()
```
### Objects
<!--rehype:wrap-class=col-span-2-->
```js
expect(value)
.toBeInstanceOf(Class)
.toMatchObject(object)
.toHaveProperty(keyPath, value)
```
### Objects
<!--rehype:wrap-class=col-span-2-->
```js
expect(value)
.toContain(item)
.toContainEqual(item)
.toHaveLength(number)
```
### Numbers
<!--rehype:wrap-class=col-span-2-->
```js
expect(value)
.toBeCloseTo(number, numDigits)
.toBeGreaterThan(number)
.toBeGreaterThanOrEqual(number)
.toBeLessThan(number)
.toBeLessThanOrEqual(number)
```
### Booleans
<!--rehype:wrap-class=col-span-2-->
```js
expect(value)
.toBeFalsy()
.toBeNull()
.toBeTruthy()
.toBeUndefined()
.toBeDefined()
```
### Strings
<!--rehype:wrap-class=col-span-2-->
```js
expect(value)
.toMatch(regexpOrString)
```
### NaN
<!--rehype:wrap-class=col-span-2-->
```js
test('当值为 NaN 时通过', () => {
expect(NaN).toBeNaN();
expect(1).not.toBeNaN();
});
```
### Others
<!--rehype:wrap-class=col-span-2-->
```js
expect.extend(matchers)
expect.any(constructor)
expect.addSnapshotSerializer(serializer)
expect.assertions(1)
```
匹配器
----
@ -293,8 +477,6 @@ expect(fn).toThrowErrorMatchingSnapshot()
### 实例
<!--rehype:wrap-class=row-span-2-->
请参阅 Jest 文档中的 [更多示例](https://jestjs.io/docs/en/tutorial-async)。
在异步测试中指定一些预期的断言是一个很好的做法,所以如果你的断言根本没有被调用,测试将会失败。
```js
@ -314,6 +496,7 @@ beforeEach(expect.hasAssertions)
```
这将验证每个测试用例至少存在一个断言。 它还可以与更具体的 `expect.assertions(3)` 声明配合使用。
请参阅 Jest 文档中的 [更多示例](https://jestjs.io/docs/en/tutorial-async)
### async/await
@ -337,8 +520,8 @@ test('async test', (done) => {
setTimeout(() => {
try {
const result = getAsyncOperationResult()
expect(result).toBe(true)
const res = getAsyncOperatResult()
expect(res).toBe(true)
done()
} catch (err) {
done.fail(err)
@ -374,18 +557,28 @@ test('call the callback', () => {
const callback = jest.fn()
fn(callback)
expect(callback).toBeCalled()
expect(callback.mock.calls[0][1].baz).toBe('pizza') // 第一次调用的第二个参数
expect(callback.mock.calls[0][1].baz)
.toBe('pizza') // 第一次调用的第二个参数
// 匹配第一个和最后一个参数,但忽略第二个参数
expect(callback).toHaveBeenLastCalledWith('meal', expect.anything(), 'margarita')
expect(callback)
.toHaveBeenLastCalledWith(
'meal',
expect.anything(),
'margarita'
)
})
```
<!--rehype:className=wrap-text -->
您还可以使用快照:
```js
test('call the callback', () => {
// mockName 在 Jest 22+ 中可用
const callback = jest.fn().mockName('Unicorn')
const callback = jest.fn()
.mockName('Unicorn')
fn(callback)
expect(callback).toMatchSnapshot()
// ->
@ -411,6 +604,7 @@ const callback = jest.fn(() => true)
```js
const callback
= jest.fn().mockReturnValue(true)
const callbackOnce
= jest.fn().mockReturnValueOnce(true)
```
@ -420,6 +614,7 @@ const callbackOnce
```js
const promise
= jest.fn().mockResolvedValue(true)
const promiseOnce
= jest.fn().mockResolvedValueOnce(true)
```
@ -427,17 +622,19 @@ const promiseOnce
他们甚至可以拒绝值:
```js
const failedPromise
= jest.fn().mockRejectedValue('Error')
const failedPromiseOnce
= jest.fn().mockRejectedValueOnce('Error')
const failedPromise =
jest.fn().mockRejectedValue('Error')
const failedPromiseOnce =
jest.fn().mockRejectedValueOnce('Error')
```
你甚至可以结合这些:
```js
const callback
= jest.fn().mockReturnValueOnce(false).mockReturnValue(true)
const callback = jest.fn()
.mockReturnValueOnce(false)
.mockReturnValue(true)
// ->
// call 1: false
// call 2+: true
@ -446,13 +643,20 @@ const callback
### 使用 `jest.mock` 方法模拟模块
```js
jest.mock('lodash/memoize', () => (a) => a) // The original lodash/memoize should exist
jest.mock('lodash/memoize', () => (a) => a, { virtual: true }) // The original lodash/memoize isnt required
// 原来的 lodash/memoize 应该存在
jest.mock(
'lodash/memoize',
() => (a) => a
)
// 不需要原始的 lodash/memoize
jest.mock(
'lodash/memoize',
() => (a) => a,
{ virtual: true }
)
```
[jest.mock docs](https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options)
> 注意:当使用 `babel-jest` 时,对 `jest.mock` 的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 `jest.doMock`。
注意:当使用 `babel-jest` 时,对 [`jest.mock`](https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options) 的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 `jest.doMock`。
### 使用模拟文件模拟模块
@ -468,22 +672,18 @@ module.exports = (a) => a
jest.mock('lodash/memoize')
```
注意:当使用 `babel-jest` 时,对 `jest.mock` 的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 `jest.doMock`
注意:当使用 `babel-jest` 时,对 `jest.mock` 的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 `jest.doMock`。[手动模拟文档](https://jestjs.io/docs/en/manual-mocks)
[手动模拟文档](https://jestjs.io/docs/en/manual-mocks)
### 模拟对象方法
### 模拟 getters 和 setters
```js
const spy = jest.spyOn(console, 'log').mockImplementation(() => {})
expect(console.log.mock.calls).toEqual([['dope'], ['nope']])
spy.mockRestore()
```
```js
const spy = jest.spyOn(ajax, 'request').mockImplementation(() => Promise.resolve({ success: true }))
expect(spy).toHaveBeenCalled()
spy.mockRestore()
const getTitle = jest.fn(() => 'pizza')
const setTitle = jest.fn()
const location = {}
Object.defineProperty(location, 'title', {
get: getTitle,
set: setTitle,
})
```
### 模拟 getter 和 setter (Jest 22.1.0+)
@ -508,8 +708,9 @@ const setTitle = jest
jest.useFakeTimers()
test('kill the time', () => {
const callback = jest.fn()
// 运行一些使用 setTimeoutsetInterval 的代码
const actual = someFunctionThatUseTimers(callback)
// 运行使用 setTimeoutsetInterval 的代码
const actual
= someFunctionThatUseTimers(callback)
// 快进直到所有定时器都执行完毕
jest.runAllTimers()
// 同步检查结果
@ -524,8 +725,9 @@ test('kill the time', () => {
jest.useFakeTimers()
test('kill the time', () => {
const callback = jest.fn()
// 运行一些使用 setTimeoutsetInterval 的代码
const actual = someFunctionThatUseTimers(callback)
// 运行使用 setTimeoutsetInterval 的代码
const actual
= someFunctionThatUseTimers(callback)
// 快进 250 毫秒
jest.advanceTimersByTime(250)
// 同步检查结果
@ -533,20 +735,29 @@ test('kill the time', () => {
})
```
对于特殊情况,请使用 [jest.runOnlyPendingTimers()](https://jestjs.io/docs/en/timer-mocks#run-pending-timers)。
> 对于特殊情况,请使用 [jest.runOnlyPendingTimers()](https://jestjs.io/docs/en/timer-mocks#run-pending-timers)。
**注意:** 您应该在测试用例中调用 `jest.useFakeTimers()` 以使用其他假计时器方法。
### 模拟 getters 和 setters
### 模拟对象方法
```js
const getTitle = jest.fn(() => 'pizza')
const setTitle = jest.fn()
const location = {}
Object.defineProperty(location, 'title', {
get: getTitle,
set: setTitle,
})
const spy = jest.spyOn(console, 'log')
.mockImplementation(() => {})
expect(console.log.mock.calls)
.toEqual([['dope'], ['nope']])
spy.mockRestore()
```
```js
const spy = jest.spyOn(ajax, 'request')
.mockImplementation(
() => Promise.resolve({success: true})
)
expect(spy).toHaveBeenCalled()
spy.mockRestore()
```
### 清除和恢复模拟
@ -558,8 +769,10 @@ Object.defineProperty(location, 'title', {
// 清除模拟使用日期
// fn.mock.calls、fn.mock.instances
fn.mockClear()
// 清除并删除任何模拟的返回值或实现
fn.mockReset()
// 重置并恢复初始实现
fn.mockRestore()
```

870
docs/nginx.md Normal file
View File

@ -0,0 +1,870 @@
NGINX 备忘清单
===
这个 nginx 快速参考备忘单显示了它的常用命和配置使用清单。
入门
----
### 服务管理
<!--rehype:wrap-class=row-span-2-->
```bash
sudo systemctl status nginx # nginx当前状态
sudo systemctl reload nginx # 重新加载 nginx
sudo systemctl restart nginx # 重启nginx
sudo nginx -t # 检查语法
nginx # 启动
nginx -s reload # 重启
nginx -s stop # 关闭进程
nginx -s quit # 平滑关闭nginx
nginx -V # 查看nginx的安装状态
```
### Docker 安装
<!--rehype:wrap-class=col-span-2-->
```bash
docker run --name some-nginx -v /some/content:/usr/share/nginx/html:ro -d nginx
```
### 简单代理
<!--rehype:wrap-class=col-span-2-->
```nginx
location / {
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
proxy_set_header Host $host;
}
```
### 全局变量
<!--rehype:wrap-class=col-span-2 row-span-4-->
| 变量 | 说明
:- | :-
`$args` | 这个变量等于请求行中的参数,同 `$query_string`
`$remote_port` | 客户端的端口
`$content_length` | 请求头中的 `Content-length` 字段
`$remote_user` | 已经经过 `Auth Basic Module` 验证的用户名
`$content_type` | 请求头中的 `Content-Type` 字段
`$request_filename` | 当前请求的文件路径,由 `root` 或alias指令与URI请求生成
`$document_root` | 当前请求在 `root` 指令中指定的值
`$scheme` | HTTP方法如httphttps
`$host` | 请求主机头字段,否则为服务器名称
`$hostname` | 主机名
`$http_user_agent` | 客户端`agent`信息
`$http_cookie` | 客户端`cookie`信息
`$server_protocol` | 请求使用的协议,通常是`HTTP/1.0``HTTP/1.1`
`$server_addr` | 服务器地址,在完成一次系统调用后可以确定这个值
`$server_name` | 服务器名称
`$server_port` | 请求到达服务器的端口号
`$limit_rate` | 这个变量可以限制连接速率
`$request_method` | 客户端请求的动作,如 GET/POST
`$request_uri` | 包含请求参数的原始URI不包含主机名`/foo/bar.php?arg=baz`
`$remote_addr` | 客户端的IP地址
`$uri` | 不带请求参数的当前URI`$uri`不包含主机名,如 `/foo/bar.html`
`$document_uri` | 与 `$uri` 相同
`$nginx_version` | `nginx` 版本
更多全局变量[查看官方文档](https://nginx.org/en/docs/varindex.html)
### 监听端口
```nginx
server {
listen 80; # 标准 HTTP 协议
listen 443 ssl; # 标准 HTTPS 协议
listen 443 ssl http2; # 对于 http2
listen [::]:80; # 使用 IPv6 在 80 上收听
# 仅收听使用 IPv6
listen [::]:80 ipv6only=on;
}
```
### 域名 (server_name)
```nginx
server {
# 监听 example.com
server_name example.com;
# 监听多个域
server_name example.com www.example.com;
# 监听所有子域
server_name *.example.com;
# 监听所有顶级域
server_name example.*;
# 监听未指定的主机名(监听 IP 地址本身)
server_name "";
}
```
### 负载均衡(简单实例)
```nginx
upstream node_js {
server 0.0.0.0:3000;
server 0.0.0.0:4000;
server 127.155.142.421;
}
```
### 负载均衡(权重)
```nginx
upstream test {
server localhost:8080 weight=9;
server localhost:8081 weight=1;
}
```
### upstream ip_hash
```nginx {2}
upstream test {
ip_hash;
server localhost:8080;
server localhost:8081;
}
```
解决负载均衡 `session` 的问题
### upstream fair
```nginx {2}
upstream backend {
fair;
server localhost:8080;
server localhost:8081;
}
```
响应时间短的优先分配
### server 可选参数
<!--rehype:wrap-class=row-span-2-->
:- | :-
:- | :-
`weight` | 访问权重数值越高,收到请求越多
`fail_timeout` | 指定的时间内必须提供响应
`max_fails` | 尝试失败服务器连接的最大次数
`down` | 标记一个服务器不再接受任何请求
`backup` | 有服务器宕机,标记的机器接收请求
配置示例
```nginx
upstream test {
server 127.0.0.1:83 weight=9; # 权重
server 127.0.0.1:83 weight=1; # 权重
# 失败超时时间
server 127.0.0.1:83 max_fails=3;
server 127.0.0.1:83 weight=3 down;
}
```
### upstream url_hash
```nginx {2,3}
upstream backend {
hash $request_uri;
hash_method crc32;
server localhost:8080;
server localhost:8081;
}
```
按访问url的hash结果来分配请求
### upstream keepalive
```nginx {4}
upstream memcached_backend {
server 127.0.0.1:11211;
server 10.0.0.2:11211;
keepalive 32;
}
```
激活缓存以连接到上游服务器
### 子文件夹中的代理
<!--rehype:wrap-class=col-span-2-->
```nginx {1,2}
location /folder/ { # / 很重要!
proxy_pass http://127.0.0.1:3000/; # / 很重要!
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
```
### 反向代理
<!--rehype:wrap-class=row-span-3-->
#### 基础
```nginx
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://0.0.0.0:3000;
# 其中 0.0.0.0:3000 是绑定在
# 0.0.0.0端口3000 列表上的 Node.js 服务器
}
}
```
#### 基础 + (upstream)
```nginx
upstream node_js {
server 0.0.0.0:3000;
# 其中 0.0.0.0:3000 是绑定在
# 0.0.0.0端口3000 列表上的 Node.js 服务器
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://node_js;
}
}
```
#### 升级连接(适用于支持 WebSockets 的应用程序)
```nginx
upstream node_js {
server 0.0.0.0:3000;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://node_js;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
```
适用于 Node.js、Streamlit、Jupyter 等
### 静态资源(传统 Web 服务器)
<!--rehype:wrap-class=col-span-2-->
```nginx
server {
listen 80;
server_name example.com;
root /path/to/website;
# root /www/data/ 示例,如果里面没有'root',它将寻找 /www/data/index.html
location / {
}
location /images/ { # 如果里面没有“root”它将寻找 /www/data/images/index.html
}
location /videos/ { # 由于里面有“root”它会寻找 /www/media/videos/index.html
root /www/media;
}
}
```
### HTTPS 协议
<!--rehype:wrap-class=col-span-2-->
大多数 SSL 选项取决于您的应用程序做什么或需要什么
```nginx
server {
listen 443 ssl http2;
server_name example.com;
ssl on;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/privkey.pem;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/fullchain.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
add_header Strict-Transport-Security max-age=15768000;
}
```
您可以使用 Let's Encrypt 轻松保护您的网站/应用程序。去 [lets-encrypt](https://certbot.eff.org/lets-encrypt/ubuntuxenial-nginx.html) 获取更多信息
### 重定向(301永久)
<!--rehype:wrap-class=row-span-2-->
将 www.example.com 重定向到 example.com
```nginx
server {
listen 80;
server_name www.example.com;
return 301 http://example.com$request_uri;
}
```
将 http 重定向到 https
```nginx
server {
listen 80;
server_name example.com;
return 301 https://example.com$request_uri;
}
```
### 重定向(302临时)
```nginx
server {
listen 80;
server_name yourdomain.com;
return 302 http://otherdomain.com;
}
```
### 永久重定向到 HTTPS 安全域
```nginx
server {
listen 80;
server_name yourdomain.com;
return 301 https://$host$request_uri;
}
```
### 重定向参数
:- | :-
:- | :-
`permanent` | 永久性重定向。日志中的状态码为 `301`
`redirect` | 临时重定向。日志中的状态码为 `302`
### HTTP 请求端真实的IP
```nginx
location / {
proxy_set_header X-Forwarded-For $remote_addr;
}
```
<!--rehype:className=wrap-text -->
示例
----
<!--rehype:body-class=cols-6-->
### websocket 的代理 keepalive
<!--rehype:wrap-class=col-span-3-->
```nginx
# Upstreams
upstream backend {
server 127.0.0.1:3000;
keepalive 5;
}
# HTTP Server
server {
server_name your_hostname.com;
error_log /var/log/nginx/rocketchat.access.log;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forward-Proto http;
proxy_set_header X-Nginx-Proxy true;
proxy_redirect off;
}
}
```
<!--rehype:className=wrap-text -->
### Apache 的反向代理
<!--rehype:wrap-class=col-span-3-->
```nginx
server {
server_name domain.tld;
access_log /log/domain.tld.access.log;
error_log /log/domain.tld.error.log;
root /var/www/domain.tld/htdocs;
# 将请求传递给 Apache 后端
location / {
proxy_pass http://backend;
}
# 使用后备处理静态文件
location ~* \.(ogg|ogv|svg|svgz|eot|otf|woff|woff2|ttf|m4a|mp4|ttf|rss|atom|jpe?g|gif|cur|heic|png|tiff|ico|zip|webm|mp3|aac|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf|swf|webp)$ {
add_header "Access-Control-Allow-Origin" "*";
access_log off;
log_not_found off;
expires max;
try_files $uri @fallback;
}
# 如果找不到文件,则回退以将请求传递给 Apache
location @fallback {
proxy_pass http://backend;
}
}
```
<!--rehype:className=wrap-text -->
### Gitlab 的反向代理
<!--rehype:wrap-class=col-span-4 row-span-3-->
```nginx
server {
#侦听的80端口
listen 80;
server_name git.example.cn;
location / {
proxy_pass http://localhost:3000;
# 以下是一些反向代理的配置可删除
proxy_redirect off;
# 后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header Host $host;
client_max_body_size 10m; # 允许客户端请求的最大单文件字节数
client_body_buffer_size 128k; # 缓冲区代理缓冲用户端请求的最大字节数
proxy_connect_timeout 300; # nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 300; # 后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 300; # 连接成功后,后端服务器响应时间(代理接收超时)
# 设置代理服务器nginx保存用户头信息的缓冲区大小
proxy_buffer_size 4k;
# proxy_buffers缓冲区网页平均在32k以下的话这样设置
proxy_buffers 4 32k;
# 高负荷下缓冲大小proxy_buffers*2
proxy_busy_buffers_size 64k;
}
}
```
### 重定向整个网站
<!--rehype:wrap-class=col-span-2-->
```nginx
server {
server_name old-site.com;
return 301 $scheme://new-site.com$request_uri;
}
```
<!--rehype:className=wrap-text -->
### 重定向单页
<!--rehype:wrap-class=col-span-2-->
```nginx
server {
location = /oldpage.html {
return 301 http://example.org/newpage.html;
}
}
```
<!--rehype:className=wrap-text -->
### 重定向整个子路径
<!--rehype:wrap-class=col-span-2-->
```nginx
location /old-site {
rewrite ^/old-site/(.*) http://example.org/new-site/$1 permanent;
}
```
<!--rehype:className=wrap-text -->
### 负载均衡
<!--rehype:wrap-class=col-span-3-->
```nginx
upstream example {
ip_hash;
# upstream的负载均衡weight是权重可以根据机器配置定义权重。
# weigth参数表示权值权值越高被分配到的几率越大。
server 192.168.122.11:8081 ;
server 127.0.0.1:82 weight=3;
server 127.0.0.1:83 weight=3 down;
server 127.0.0.1:84 weight=3; max_fails=3 fail_timeout=20s;
server 127.0.0.1:85 weight=4;;
keepalive 32;
}
server {
#侦听的80端口
listen 80;
server_name git.example.cn;
location / {
# 在这里设置一个代理,和 upstream 的名字一样
proxy_pass http://example;
}
}
```
### 内容缓存
<!--rehype:wrap-class=col-span-3-->
允许浏览器基本上永久地缓存静态内容。 Nginx 将为您设置 Expires 和 Cache-Control 头信息
```nginx {3}
location /static {
root /data;
expires max;
}
```
如果要求浏览器永远不会缓存响应(例如用于跟踪请求),请使用 `-1`
```nginx {3}
location = /empty.gif {
empty_gif;
expires -1;
}
```
### 跨域问题
<!--rehype:wrap-class=col-span-3-->
```nginx
server {
listen 80;
server_name api.xxx.com;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET,POST,HEAD';
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
}
```
### 重定向 URI 来解决跨域问题
<!--rehype:wrap-class=col-span-3 row-span-2-->
```nginx
upstream test {
server 127.0.0.1:8080;
server localhost:8081;
}
server {
listen 80;
server_name api.xxx.com;
location / {
root html; # 去请求../html文件夹里的文件
index index.html index.htm; # 首页响应地址
}
# 用于拦截请求,匹配任何以 /api/开头的地址,
# 匹配符合以后,停止往下搜索正则。
location ^~/api/{
# 代表重写拦截进来的请求,并且只能对域名后边的除去传递的参数外的字符串起作用
# 例如www.a.com/api/msg?meth=1&par=2重写只对/api/msg重写。
# rewrite后面的参数是一个简单的正则 ^/api/(.*)$
# $1代表正则中的第一个()$2代表第二个()的值,以此类推。
rewrite ^/api/(.*)$ /$1 break;
# 把请求代理到其他主机
# 其中 http://www.b.com/ 写法和 http://www.b.com写法的区别如下
# 如果你的请求地址是他 http://server/html/test.jsp
# 配置一: http://www.b.com/ 后面有“/”
# 将反向代理成 http://www.b.com/html/test.jsp 访问
# 配置一: http://www.b.com 后面没有有“/”
# 将反向代理成 http://www.b.com/test.jsp 访问
proxy_pass http://test;
# 如果 proxy_pass URL 是 http://a.xx.com/platform/ 这种情况
# proxy_cookie_path应该设置成 /platform/ / (注意两个斜杠之间有空格)。
proxy_cookie_path /platfrom/ /;
# 设置 Cookie 头通过
proxy_pass_header Set-Cookie;
}
}
```
### 跳转到带 www 的域上面
<!--rehype:wrap-class=col-span-3-->
```nginx
server {
listen 80;
# 配置正常的带www的域名
server_name www.wangchujiang.com;
root /home/www/wabg/download;
location / {
try_files $uri $uri/ /index.html =404;
}
}
server {
# 将不带 www 的 wangchujiang.com
# 永久性重定向到 https://www.wangchujiang.com
server_name wangchujiang.com;
rewrite ^(.*) https://www.wangchujiang.com$1 permanent;
}
```
### 代理转发
<!--rehype:wrap-class=col-span-2 row-span-2-->
```nginx
upstream server-api {
# api 代理服务地址
server 127.0.0.1:3110;
}
upstream server-resource {
# 静态资源 代理服务地址
server 127.0.0.1:3120;
}
server {
listen 3111;
server_name localhost; # 这里指定域名
root /home/www/server-statics;
# 匹配 api 路由的反向代理到API服务
location ^~/api/ {
rewrite ^/(.*)$ /$1 break;
proxy_pass http://server-api;
}
# 假设这里验证码也在API服务中
location ^~/captcha {
rewrite ^/(.*)$ /$1 break;
proxy_pass http://server-api;
}
# 假设你的图片资源全部在另外一个服务上面
location ^~/img/ {
rewrite ^/(.*)$ /$1 break;
proxy_pass http://server-resource;
}
# 路由在前端,后端没有真实路由,
# 路由不存在的 404 状态的页面返回 /index.html
# 使用场景,用在 React/Vue项目没有真实路由
location / {
try_files $uri $uri/ /index.html =404;
# 空格很重要 ^
}
}
```
### 屏蔽 IP
<!--rehype:wrap-class=col-span-4-->
可以放到 `http`, `server`, `location`, `limit_except` 语句块
```nginx
include blockip.conf;
```
在 `blockip.conf` 里面输入内容,如:
```nginx
deny 165.91.122.67;
deny IP; # 屏蔽单个 ip 访问
allow IP; # 允许单个 ip 访问
deny all; # 屏蔽所有 ip 访问
allow all; # 允许所有 ip 访问
deny 123.0.0.0/8; # 屏蔽整个段即从 123.0.0.1 到 123.255.255.254 访问的命令
deny 124.45.0.0/16; # 屏蔽IP段即从 123.45.0.1 到 123.45.255.254 访问的命令
deny 123.45.6.0/24; # 屏蔽IP段即从 123.45.6.1 到 123.45.6.254 访问的命令
# 如果你想实现这样的应用除了几个IP外其他全部拒绝
allow 1.1.1.1;
allow 1.1.1.2;
deny all;
```
### 强制将 http 重定向到 https
<!--rehype:wrap-class=col-span-4-->
```nginx
server {
listen 80;
server_name example.com;
rewrite ^ https://$http_host$request_uri? permanent; # 强制将 http 重定向到 https
# 在错误页面和“服务器”响应头字段中启用或禁用发射nginx版本。 防止黑客利用版本漏洞攻击
server_tokens off;
}
```
### 代理转发连接替换
<!--rehype:wrap-class=col-span-2-->
```nginx
location ^~/api/upload {
rewrite ^/(.*)$ /wfs/v1/upload break;
proxy_pass http://wfs-api;
}
```
将地址 `/api/upload` 替换为 `/wfs/v1/upload`
### 爬虫 User-Agent 过滤
<!--rehype:wrap-class=col-span-4-->
```nginx
location / {
if ($http_user_agent ~* "python|curl|java|wget|httpclient|okhttp") {
return 503;
}
# 正常处理
# ...
}
```
### 图片防盗链
<!--rehype:wrap-class=col-span-2-->
```nginx
location ~* \.(gif|jpg|png|swf|flv)$ {
root html;
valid_referers none blocked *.nginx.com;
if ($invalid_referer) {
rewrite ^/ www.nginx.cn;
# return 404;
}
}
```
### 虚拟目录配置
<!--rehype:wrap-class=col-span-2-->
```nginx
location /img/ {
alias /var/www/image/;
}
# 访问 /img/ 目录里面的文件时,
# 会自动去 /var/www/image/ 目录找文件
location /img/ {
root /var/www/image;
}
# 访问 /img/ 目录下的文件时,
# 会去 /var/www/image/img/ 目录下找文件
```
### 屏蔽文件目录
<!--rehype:wrap-class=col-span-2 row-span-2-->
通用备份和归档文件
```nginx
location ~* "\.(old|orig|original|php#|php~|php_bak|save|swo|aspx?|tpl|sh|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rdf)$" {
deny all;
}
```
<!--rehype:className=wrap-text -->
拒绝访问 `.git` 和 `.svn` 目录
```nginx
location ~ (.git|.svn) {
deny all;
}
```
<!--rehype:className=wrap-text -->
拒绝访问隐藏文件和目录
```nginx
location ~ /\.(?!well-known\/) {
deny all;
}
```
### 防盗图配置
<!--rehype:wrap-class=col-span-4-->
```nginx
location ~ \/public\/(css|js|img)\/.*\.(js|css|gif|jpg|jpeg|png|bmp|swf) {
valid_referers none blocked *.jslite.io;
if ($invalid_referer) {
rewrite ^/ http://wangchujiang.com/piratesp.png;
}
}
```
### 阻止常见攻击
<!--rehype:wrap-class=col-span-2-->
#### base64编码的网址
```nginx
location ~* "(base64_encode)(.*)(\()" {
deny all;
}
```
#### javascript eval() url
```nginx
location ~* "(eval\()" {
deny all;
}
```
### Gzip 配置
<!--rehype:wrap-class=col-span-4 row-span-2-->
```nginx
gzip on;
gzip_buffers 16 8k;
gzip_comp_level 6;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
text/xml application/xml application/atom+xml application/rss+xml application/xhtml+xml image/svg+xml
text/javascript application/javascript application/x-javascript
text/x-json application/json application/x-web-app-manifest+json
text/css text/plain text/x-component
font/opentype application/x-font-ttf application/vnd.ms-fontobject
image/x-icon;
gzip_disable "msie6";
```
### 使网站不可索引
<!--rehype:wrap-class=col-span-2-->
```nginx
add_header X-Robots-Tag "noindex";
location = /robots.txt {
return 200 "User-agent: *\nDisallow: /\n";
}
```
另见
---
- [Nginx 安装维护入门学习笔记](https://jaywcjlove.github.io/nginx-tutorial) _(jaywcjlove.github.io)_
- [](https://virtubox.github.io/advanced-nginx-cheatsheet/) _(virtubox.github.io)_

View File

@ -138,6 +138,16 @@ npm unpublish <package-name>@<version>
注意:如果您取消发布整个包,则必须在 24 小时后才能发布该包的任何新版本。
### 发布包 npmjs.org
```bash
npm publish
# 第一次需要指定公开参数
npm publish --access public
```
发布公开包,到 npmjs.org
配置
---

View File

@ -101,7 +101,7 @@ https://registry.npmjs.org/[包名]/-/[包名]-[version].tgz
鼓励使用开源 [(OSI-approved)](https://opensource.org/licenses/alphabetical) 许可证,除非你有特别的原因不用它。 如果你开发的包是你工作的一部分,最好和公司讨论后再做决定。
**license字段必须是以下之一:**
#### **license字段必须是以下之一**
- 如果你使用标准的许可证,需要一个有效地 [SPDX 许可证标识](https://spdx.org/licenses/)。
- 如果你用多种标准许可证,需要有效的 [SPDX 许可证表达式2.0语法表达式](https://www.npmjs.com/package/spdx)。

View File

@ -1,7 +1,7 @@
Quick Reference 备忘清单
===
这是您可以在 Quick Reference 备忘单上使用的样式参考,快速参与贡献
这是您可以在 Quick Reference 备忘单上使用的样式参考,快速参与[贡献](https://github.com/jaywcjlove/reference/blob/main/CONTRIBUTING.md)
入门
---
@ -51,8 +51,8 @@ HTML 存放在仓库根目录下的 `dist` 目录中,将 `dist/index.html` 静
#### 语法
`<!--rehype:` + `key=value` + `&` + `key=value` + `-->`
`标识开始` + `参数` + `分隔符` + `参数` + `标识结束`
`<!--rehype:` _+_ `key=value` _+_ **`&`** _+_ `key=value` _+_ `-->`
`标识开始` + `参数` + `分隔符(&)` + `参数` + `标识结束`
#### 示例
@ -72,7 +72,6 @@ HTML 存放在仓库根目录下的 `dist` 目录中,将 `dist/index.html` 静
```
<!--rehype:className=wrap-text -->
#### 参数说明
类 | 说明
@ -209,6 +208,7 @@ const school = <div>学校</div>;
`<yel>` | <yel>黄色</yel>
`<pur>` | <pur>紫色</pur>
`<code>` 或 <code>\`\`</code> | <code>绿</code>`色`
`<del>``~~删除~~` | <del>~~红色~~</del>
<!--rehype:className=shortcuts-->
@ -584,6 +584,25 @@ H2 部分
`<!--rehype:className=cols-4-->`
### 列表步骤
<!--rehype:wrap-class=row-span-2-->
- **重命名为 new_name**
```bash
$ git branch -m <new_name>
```
- 推送和**重置**
```bash
$ git push origin -u <new_name>
```
- 删除远程分支
```bash
$ git push origin --delete <old>
```
<!--rehype:className=style-timeline-->
`<!--rehype:className=style-timeline-->`
### 没有标记
- Item 1
@ -592,10 +611,22 @@ H2 部分
- Item 4
- Item 5
- Item 6
- Item 7
- Item 8
- Item 9
<!--rehype:className=cols-3 style-none-->
`<!--rehype:className=cols-3 style-none-->`
### 圆圈标记
- Item 1
- Item 2
- Item 3
<!--rehype:className=style-round-->
`<!--rehype:className=style-round-->`
H2 部分 - 5列效果展示
---
<!--rehype:body-class=cols-5-->

View File

@ -12,9 +12,9 @@ React 备忘清单
React 是一个用于构建用户界面的 JavaScript 库。
- [React 官方文档](https://reactjs.org/) _(reactjs.org)_
- [Styled Components 备忘清单](./styled-components.md) _(jaywcjlove.github.io)_
```js
import React from 'react'
import {createRoot} from 'react-dom/client'
import App from './App'
```
@ -46,14 +46,15 @@ import ReactDOM from 'react-dom'
export class Hello extends Component {
...
}
export default function World() {
/* ... */
}
```
使用 `export` 或者 `export default` 导出 `Hello` 组件
使用 `export` 导出 **`Hello`**`export default` 导出 **`World`** 组件
```jsx
import { Hello } from './hello.js';
const Example = <Hello />;
import World, { Hello } from './hello.js';
```
使用 `import` 导入 `Hello` 组件,在示例中使用。

1110
docs/styled-components.md Normal file

File diff suppressed because it is too large Load Diff

150
docs/sublime-text.md Normal file
View File

@ -0,0 +1,150 @@
Sublime Text 备忘清单
===
这个 [Sublime Text](https://www.sublimetext.com/) 快速参考备忘单显示了它的键盘快捷键和命令。
## 快捷键
### 文本编辑初学者
<!--rehype:wrap-class=row-span-3-->
[Sublime Text](https://www.sublimetext.com/) 是一个用于代码、标记的复杂文本编辑器。
快捷键 | 说明
:- | -
`⌘ D` | 选择单词(重复包括单词的下一个实例)
`⌘ L` | 选择行(重复以包括下一行)
`⌘ ⇧ L` | 将选择拆分为多行(多行编辑)
`⌘ ⇧ A` | 选择标签内的文本(重复以展开)
`⌃ ⇧ M` | 选择大括号或尖括号(重复展开)
`⌘ X` | 剪切一行
`⌃ M` | 转到匹配的括号
`⌃ ↩︎` or `↩︎` | 在后面插入行
`⌘ ↵` | 在后面插入行
`⇧ ⌘ ↵` | 在前面插入行
`⇧ ⌥ ▲` | 选择当前行光标之前
`⇧ ⌥ ▼` | 选择当前行光标之后
`⇧ ⌃ M` | 选择当前括号的所有内容
`⌥ ⇠/⇢` | 进行逐词移动,相应的
`⌥ ⇧ ⇠/⇢` | 进行逐词选择
`⌘ U` | 返回到历史光标位置(撤销)
`⌃ M` | 快速的在起始括号和结尾括号间切换
`⌃ ⇧ M` | 则可以快速选择括号间的内容
`⌃ ⇧ J` | 对于缩进型语言(例如Python)可以使用
`⌃ ⌘ D` | 复制整行
<!--rehype:className=shortcuts-->
查看:[Sublime Text](https://www.sublimetext.com/) 官网
### 代码折叠
快捷键 | 说明
:- | -
`⌘ Alt [` | 折叠最近的块
`⌘ Alt ]` | 展开最近的块
`⌘ K ⌘ 1` | 折叠所有第一级代码块
`⌘ K ⌘ 2` | 折叠所有二级代码块
`⌘ K ⌘ 3` | 折叠所有第三级代码块(等)
`⌘ K ⌘ T` | 折叠所有 HTML 属性
`⌘ K ⌘ 0` | 展开一切
`⌘ K 0` | 代码展开
<!--rehype:className=shortcuts-->
### macOS 键盘符号
快捷键 | 说明
:- | -
`⌘` | Command()
`⌃` | Control
`⌥` | Option(alt)
`⇧` | Shift
`⇪` | Caps Lock(大写)
`fn` | 功能键就是fn
`↩︎` | return/Enter
<!--rehype:className=shortcuts-->
### 编辑
快捷键 | 说明
:- | -
`⌘ ⇧ D` | 复制当前行/选择
`⌘ ⇧ K` | 删除当前行/选择
`⇧ del` | 删除当前行/选择
`⌘ ⇧ ▲` | 移动队列
`⌘ ⇧ ▼` | 下移一行
`⌘ ▼/▲`| 移动到首行/尾行
<!--rehype:className=shortcuts-->
### 转到
快捷键 | 说明
:- | -
`⌘ P` | 去任何地方
`⌘ G` | 转到行号
`⌘ R` | 转到符号
`⌘ P, :` | 转到行号(`:`之后输入数字)
`⌘ P, #` | 转到并列出字符串模糊匹配(`#`之后输入字符)
`⌘ P, @` | 转到并列出符号(`@`之后开始输入符号名称)
<!--rehype:className=shortcuts-->
### 选择(Selecting)
- `⌘ + D`
选择光标所在的单词,并高亮该词出现的所有位置
- `⌘ + D`
择该词出现的下一个位置
- `⌘ + U` 进行回退使用Esc退
<!--rehype:className=style-timeline shortcuts-->
----
快捷键 | 说明
:- | -
`⌃ K` / `⌘ K K` | 从光标处删除到行末尾
<!--rehype:className=shortcuts-->
### 拆分窗口
快捷键 | 说明
:- | -
`⇧ ⌥ 2` | 将视图拆分为两列
`⇧ ⌥ 1` | 将视图还原为单列
`⇧ ⌥ 5` | 将视图设置为网格4 组)
`⌃ 2` | 跳到第 2 组
`⇧ ⌃ 2` | 将文件移动到组 2
<!--rehype:className=shortcuts-->
### 文本操作
快捷键 | 说明
:- | -
`⌃ K ⌃ L` | 转换为小写
`⌃ K ⌃ U` | 转换为大写
`⇧ ⌃ K` | 删除行
`⌃BACKSPACE` | 向后删除单词
`⌃DEL` | 删除单词转发
<!--rehype:className=shortcuts-->
### 命令行中启动编辑器
<!--rehype:wrap-class=col-span-2-->
```bash
sudo ln -s /Applications/Sublime\ Text.app/Contents/SharedSupport/bin/subl\
/usr/local/bin/subl
```
<!--rehype:className=wrap-text -->
#### 在命令行中使用 **subl** 命令
```bash
$ subl .
$ subl README.md
```
软链放到这个目录 `/usr/local/bin/subl`,这是因为 `Rootless` 机制,不能存放到 ~~`/usr/bin/subl`~~ 位置。
另见
----
- [Sublime Text 官网](https://www.sublimetext.com/) _(sublimetext.com)_
- [Sublime 编辑器快捷键](https://jaywcjlove.github.io/handbook/Shortcuts/sublime.html) _(jaywcjlove.github.io)_

View File

@ -1258,6 +1258,7 @@ class MyComponent extends React.Component<Props, {}> {
```
### 泛型组件
<!--rehype:wrap-class=col-span-2-->
```tsx
// 一个泛型组件

524
docs/yaml.md Normal file
View File

@ -0,0 +1,524 @@
YAML 备忘清单
====
这是理解和编写 YAML 格式配置文件的快速参考备忘单。
入门
-----------
### 介绍
[YAML](https://yaml.org/) 是一种数据序列化语言,旨在供人类直接读写
- YAML 不允许使用制表符
- 元素部分之间必须有空间
- YAML 区分大小写
-`.yaml``.yml` 扩展名结束您的 YAML 文件
- YAML 是 JSON 的超集
- Ansible playbook 是 YAML 文件
<!--rehype:className=style-round-->
### 标量类型
<!--rehype:wrap-class=row-span-2-->
```yaml
n1: 1 # 整数
n2: 1.234 # 浮点
s1: 'abc' # 字符串
s2: "abc" # 字符串
s3: abc # 字符串
b: false # 布尔类型
d: 2015-04-05 # 日期类型
```
#### ↓ 等效的 JSON
```json
{
"n1": 1,
"n2": 1.234,
"s1": "abc",
"s2": "abc",
"s3": "abc",
"b": false,
"d": "2015-04-05"
}
```
使用空格缩进。 元素部分之间必须有空间。
### 变量
```yaml
some_thing: &VAR_NAME foobar
other_thing: *VAR_NAME
```
#### ↓ 等效的 JSON
```json {.wrap}
{
"some_thing": "foobar",
"other_thing": "foobar"
}
```
### 注释
```yaml
# A single line comment example
# block level comment example
# comment line 1
# comment line 2
# comment line 3
```
### 多行字符串
```yaml
description: |
hello
world
```
#### ↓ 等效的 JSON
```json {.wrap}
{"description": "hello\nworld\n"}
```
### 继承
<!--rehype:wrap-class=row-span-2-->
```yaml
parent: &defaults
a: 2
b: 3
child:
<<: *defaults
b: 4
```
#### ↓ 等效的 JSON
```json {.wrap}
{
"parent": {
"a": 2,
"b": 3
},
"child": {
"a": 2,
"b": 4
}
}
```
### 参考
<!--rehype:wrap-class=row-span-2-->
```yaml
values: &ref
- Will be
- reused below
other_values:
i_am_ref: *ref
```
#### ↓ 等效的 JSON
```json {.wrap}
{
"values": [
"Will be",
"reused below"
],
"other_values": {
"i_am_ref": [
"Will be",
"reused below"
]
}
}
```
### 折叠的字符串
```yaml
description: >
hello
world
```
#### ↓ 等效的 JSON
```json {.wrap}
{"description": "hello world\n"}
```
### 两份文件
```yaml
---
document: this is doc 1
---
document: this is doc 2
```
YAML使用`---`将指令与文档内容分开。
YAML Collections
-----------
### 序列
```yaml
- Mark McGwire
- Sammy Sosa
- Ken Griffey
```
#### ↓ 等效的 JSON
```json
[
"Mark McGwire",
"Sammy Sosa",
"Ken Griffey"
]
```
### 映射
```yaml
hr: 65 # Home runs
avg: 0.278 # Batting average
rbi: 147 # Runs Batted In
```
#### ↓ 等效的 JSON
```json
{
"hr": 65,
"avg": 0.278,
"rbi": 147
}
```
### 映射到序列
```yaml
attributes:
- a1
- a2
methods: [getter, setter]
```
#### ↓ 等效的 JSON
```json
{
"attributes": ["a1", "a2"],
"methods": ["getter", "setter"]
}
```
### 映射序列
```yaml
children:
- name: Jimmy Smith
age: 15
- name: Jimmy Smith
age: 15
-
name: Sammy Sosa
age: 12
```
#### ↓ 等效的 JSON
```json
{
"children": [
{"name": "Jimmy Smith", "age": 15},
{"name": "Jimmy Smith", "age": 15},
{"name": "Sammy Sosa", "age": 12}
]
}
```
### 序列的序列
```yaml
my_sequences:
- [1, 2, 3]
- [4, 5, 6]
-
- 7
- 8
- 9
- 0
```
#### ↓ 等效的 JSON
```json
{
"my_sequences": [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9, 0]
]
}
```
### 映射的映射
```yaml
Mark McGwire: {hr: 65, avg: 0.278}
Sammy Sosa: {
hr: 63,
avg: 0.288
}
```
#### ↓ 等效的 JSON
```json
{
"Mark McGwire": {
"hr": 65,
"avg": 0.278
},
"Sammy Sosa": {
"hr": 63,
"avg": 0.288
}
}
```
### 嵌套集合
```yaml
Jack:
id: 1
name: Franc
salary: 25000
hobby:
- a
- b
location: {country: "A", city: "A-A"}
```
#### ↓ 等效的 JSON
```json
{
"Jack": {
"id": 1,
"name": "Franc",
"salary": 25000,
"hobby": ["a", "b"],
"location": {
"country": "A", "city": "A-A"
}
}
}
```
### 无序集
```yaml
set1: !!set
? one
? two
set2: !!set {'one', "two"}
```
#### ↓ 等效的 JSON
```json
{
"set1": {"one": null, "two": null},
"set2": {"one": null, "two": null}
}
```
集合表示为一个映射,其中每个键都与一个空值相关联
### 有序映射
```yaml
ordered: !!omap
- Mark McGwire: 65
- Sammy Sosa: 63
- Ken Griffy: 58
```
#### ↓ 等效的 JSON
```json
{
"ordered": [
{"Mark McGwire": 65},
{"Sammy Sosa": 63},
{"Ken Griffy": 58}
]
}
```
YAML 参考
--------------
### 条款
- 序列又名数组或列表
- 标量又名字符串或数字
- 映射又名哈希或字典
<!--rehype:className=style-round-->
基于 YAML.org [refcard](https://yaml.org/refcard.html)。
### 文档指标
:- | :-
:- | :-
`%` | 指令指标
`---` | 文档标题
`...` | 文档终结者
### 收集指标
<!--rehype:wrap-class=row-span-2-->
:- | :-
:- | :-
`?` | 关键指标
`:` | 价值指标
`-` | 嵌套系列条目指示器
`,` | 单独的内联分支条目
`[]` | 环绕串联系列分支
`{}` | 环绕在线键控分支
### 别名指标
:- | :-
:- | :-
`&` | 锚属性
`*` | 别名指示符
### 特殊键
:- | :-
:- | :-
`=` | 默认“值”映射键
`<<` | 合并来自另一个映射的键
### 标量指标
:- | :-
:- | :-
`''` | 环绕内联未转义标量
`"` | 环绕内嵌转义标量
`|` | 块标量指示器
`>` | 折叠标量指示器
`-` | 剥离 chomp 修饰符(`|-` 或 `>-`
`+` | 保留 chomp 修饰符(`|+` 或 `>+`
`1-9` | 显式缩进修饰符(`|1` 或 `>2`)。 <br/> 修饰符可以组合(`|2-`, `>+1`
### 标签属性(通常未指定)
<!--rehype:wrap-class=col-span-2-->
:- | :-
:- | :-
`none` | 未指定的标签(由应用程序自动解析)
`!` | 非特定标签(默认情况下,`!!map`/`!!seq`/`!!str`
`!foo` | 主要(按照惯例,表示本地 `!foo` 标记)
`!!foo` | 次要的(按照惯例,表示 `tag:yaml.org,2002:foo`
`!h!foo` | 需要 `%TAG !h! <prefix>`(然后表示 `<prefix>foo`
`!<foo>` | 逐字标记始终表示“foo”
### 杂项指标
| | |
|-----|-----------------------------|
| `#` | 一次性评论指示器 |
| <code>\`@</code> | 两者都保留供将来使用 |
### 核心类型(默认自动标签)
<!--rehype:wrap-class=row-span-2-->
| | |
|---------|------------------------------------------|
| `!!map` | `{Hash table, dictionary, mapping}` |
| `!!seq` | `{List, array, tuple, vector, sequence}` |
| `!!str` | Unicode 字符串 |
### 转义码
<!--rehype:wrap-class=row-span-3-->
#### Numeric
- `\x12` (8-bit)
- `\u1234` (16-bit)
- `\U00102030` (32-bit)
<!--rehype:className=cols-2 style-none-->
#### Protective
- `\\` (\\)
- `\"` (")
- `\ ` ( )
- `\<TAB>` (TAB)
<!--rehype:className=cols-3 style-none-->
#### C
- `\0` (NUL)
- `\a` (BEL)
- `\b` (BS)
- `\f` (FF)
- `\n` (LF)
- `\r` (CR)
- `\t` (TAB)
- `\v` (VTAB)
<!--rehype:className=cols-3 style-none-->
#### 额外的
- `\e` (ESC)
- `\_` (NBSP)
- `\N` (NEL)
- `\L` (LS)
- `\P` (PS)
<!--rehype:className=cols-3 style-none-->
### 更多类型
| | |
|----------|-----------------------------|
| `!!set` | `{cherries, plums, apples}` |
| `!!omap` | `[one: 1, two: 2]` |
### 与语言无关的标量类型
<!--rehype:wrap-class=col-span-2-->
| | |
|---------------------------|--------------------------------------------|
| `{~, null}` | 空(无值)。 |
| `[1234, 0x4D2, 02333]` | [十进制整数、十六进制整数、八进制整数] |
| `[1_230.15, 12.3015e+02]` | [固定浮点数,指数浮点数] |
| `[.inf, -.Inf, .NAN]` | [无穷大(浮点数),负数,不是数字] |
| `{Y, true, Yes, ON}` | 布尔真 |
| `{n, FALSE, No, off}` | 布尔假 |
另见
---
- [YAML Reference Card](https://yaml.org/refcard.html) _(yaml.org)_
- [Learn X in Y minutes](https://learnxinyminutes.com/docs/yaml/) _(learnxinyminutes.com)_
- [YAML lint online](http://www.yamllint.com/) _(yamllint.com)_

View File

@ -1,6 +1,6 @@
{
"name": "reference",
"version": "1.0.1",
"version": "1.1.0",
"description": "为开发人员分享快速参考备忘单(主要是方便自己)。",
"author": "jaywcjlove",
"license": "MIT",

3
scripts/assets/emmet.svg Normal file
View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" height="1em" width="1em" viewBox="0 0 153 151">
<path d="M76.2378757,0 C118.342892,0 152.475751,33.7082594 152.475751,75.2895046 C152.475751,116.87075 118.342892,150.579009 76.2378757,150.579009 C34.1328596,150.579009 0,116.87075 0,75.2895046 C0,33.7082594 34.1328596,0 76.2378757,0 Z M60.5934369,46.9019586 L19.8384036,56.9645627 L92.6150779,128.835332 L102.803239,88.5872762 L94.3131047,80.2021662 L87.0356763,108.950356 L70.5395345,92.6594199 L75.3909542,73.9732442 L56.2267408,78.5252622 L39.7305989,62.2343264 L68.8415078,55.0474265 L60.5934369,46.9019586 Z M116.873372,33.007443 L76.1189361,43.0694569 L84.367007,51.2149248 L102.561176,47.1421909 L98.1944795,64.8703887 L106.684613,73.2549084 L116.873372,33.007443 Z" transform="translate(0 .421)"/>
</svg>

After

Width:  |  Height:  |  Size: 824 B

3
scripts/assets/nginx.svg Normal file
View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" height="1em" width="1em" viewBox="0 0 46 52">
<path d="M21.6686953,0.373850863 C22.4859141,-0.124616954 23.5140859,-0.124616954 24.3575391,0.373850863 L44.6555781,12.0199042 C45.4992109,12.491911 46,13.3837179 46,14.3541925 L46,37.6459416 C46,38.6164162 45.4992109,39.5084019 44.6555781,39.9804087 L24.3575391,51.6262832 C23.5403203,52.1245723 22.5123281,52.1245723 21.6686953,51.6262832 L1.37083594,39.9804087 C0.948929687,39.7444053 0.606265625,39.4295553 0.369078125,39.009934 C0.105476562,38.5903128 0,38.1444094 0,37.672045 L0,14.3541925 C0,13.3837179 0.500789062,12.491911 1.37101563,12.0199042 Z M32.1078203,14.5377872 C31.4147694,14.5348957 30.749258,14.8075453 30.2591927,15.2951641 C29.7691273,15.782783 29.4951098,16.444972 29.4980391,17.134563 L29.4980391,30.0655834 L18.5843594,17.0821774 L17.7937344,16.1378062 C16.9238672,15.0623815 15.4739687,14.5640925 14.2348437,14.5640925 C12.5215234,14.5640925 11.2825549,15.6919028 11.2825549,17.0821774 L11.2825549,34.8918533 C11.2796492,35.5814132 11.5536421,36.2435748 12.0436685,36.7311885 C12.5336949,37.2188021 13.1991599,37.4914728 13.8921797,37.4886291 C14.5852306,37.4915206 15.250742,37.218871 15.7408073,36.7312522 C16.2308727,36.2436333 16.5048902,35.5814443 16.5019609,34.8918533 L16.5019609,21.9869363 L28.2062656,35.8886101 C29.0761328,36.9640348 30.5260312,37.4623238 31.7651562,37.4623238 C33.4784766,37.4623238 34.7174451,36.3345135 34.7174451,34.9444177 L34.7174451,17.134563 C34.7203508,16.4450031 34.4463579,15.7828415 33.9563315,15.2952278 C33.4663051,14.8076142 32.8008401,14.5349435 32.1078203,14.5377872 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor" height="1em" width="1em">
<path d="m16.214 6.762-.075.391c-.116.741-.074.953.244 1.228l.307.254-.318 1.418c-.19.846-.423 1.555-.571 1.788-.127.201-.275.497-.307.656-.053.19-.233.381-.508.55-.243.138-.72.508-1.058.805-.27.243-.456.392-.557.456l-.33.261a1.4 1.4 0 0 0-.189.411c-.023.107-.01.178.024.23.033.05.09.085.168.107a.954.954 0 0 0 .282.023 3 3 0 0 0 .632-.112c.07-.019.125-.037.173-.053.074-.091.245-.263.548-.562.804-.793 1.111-1.227.794-1.11-.117.042-.064-.064.137-.276.424-.413.667-1.037 1.175-2.994.402-1.545.402-1.567.698-1.567.139 0 .532.024.532.024V6.762h-.902zm3.839 3.165c-.064 0-.17.096-.233.202-.116.19.021.306 1.767 1.396 1.037.657 1.873 1.217 1.852 1.26-.021.031-.868.582-1.883 1.217-1.842 1.142-1.852 1.153-1.683 1.386.212.275 0 .37 2.391-1.122L24 13.155v-.836l-1.937-1.196c-1.047-.656-1.957-1.185-2.01-1.196zm-16.085.117c-.053 0-.963.54-2.01 1.185L0 12.425v.836l1.947 1.217c1.08.666 1.99 1.217 2.032 1.217.042 0 .127-.096.212-.212.127-.201.02-.286-1.768-1.418C.72 12.996.54 12.848.71 12.732c.106-.074.91-.572 1.778-1.111 1.979-1.217 1.873-1.133 1.714-1.387-.063-.105-.17-.2-.233-.19zm8.684.023c-.292-.002-.92.443-2.8 1.978-.081.193-.088.326-.051.412.024.059.068.1.129.13.06.03.138.048.224.055.171.015.373-.012.536-.044l.11-.025a.386.386 0 0 1 .144-.118c.116-.064.603-.508 1.09-.984.857-.868 1.058-1.26.709-1.387a.24.24 0 0 0-.09-.017zm2.196.603c-.257.007-.72.305-1.513.938-.398.323-.65.497-.785.533l-.524.414c-.197.36-.226.583-.174.706a.25.25 0 0 0 .138.134.644.644 0 0 0 .24.045 2.18 2.18 0 0 0 .58-.085 3.466 3.466 0 0 0 .291-.092l.029-.012.053-.028c.1-.129.33-.372.618-.652.91-.878 1.375-1.502 1.28-1.735-.043-.113-.117-.17-.233-.166zm-2.424 1.08c-.074.008-.24.136-.539.398-.432.382-.903.602-1.066.504a3.97 3.97 0 0 1-.114.024c-.166.033-.373.06-.558.045a.708.708 0 0 1-.252-.063.337.337 0 0 1-.168-.17c-.037-.09-.037-.202.005-.345l-.65.534-1.471 1.217v1.973l4.82-3.797a.41.41 0 0 1 .016-.123c.037-.134.035-.202-.023-.196zm2.074.639c-.073 0-.195.103-.39.31-.265.283-.682.557-.903.613l-.034.018a2.191 2.191 0 0 1-.11.042c-.06.02-.138.044-.228.068-.18.049-.404.094-.604.089a.732.732 0 0 1-.275-.054.344.344 0 0 1-.184-.18c-.058-.139-.035-.334.092-.611L7.61 16.033v1.205h1.868l3.962-3.112c.103-.114.258-.27.467-.465.56-.519.687-.698.687-.963 0-.206-.023-.31-.096-.31zm.943 1.95-.339.338c-.19.18-.529.402-.761.497l-.046.02-.003.005-.01.01c-.009.007-.013.008-.02.011a3.432 3.432 0 0 1-.282.093 3.058 3.058 0 0 1-.65.115 1.035 1.035 0 0 1-.31-.027.364.364 0 0 1-.218-.144c-.048-.074-.062-.173-.035-.295a1.11 1.11 0 0 1 .095-.25l-3.197 2.526h4.252l.508-.582c.698-.814 1.016-1.396 1.016-1.894z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor" height="1em" width="1em">
<path d="M20.953.004a.397.397 0 0 0-.18.017L3.225 5.585c-.175.055-.323.214-.402.398a.42.42 0 0 0-.06.22v5.726a.42.42 0 0 0 .06.22c.079.183.227.341.402.397l7.454 2.364-7.454 2.363c-.255.08-.463.374-.463.655v5.688c0 .282.208.444.463.363l17.55-5.565c.237-.075.426-.336.452-.6.003-.022.013-.04.013-.065V12.06c0-.281-.208-.575-.463-.656L13.4 9.065l7.375-2.339c.255-.08.462-.375.462-.656V.384c0-.211-.117-.355-.283-.38z"/>
</svg>

After

Width:  |  Height:  |  Size: 532 B

4
scripts/assets/xpath.svg Normal file
View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" height="1em" width="1em">
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M10 2a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H8v2h5V9a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-6a1 1 0 0 1-1-1v-1H8v6h5v-1a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-6a1 1 0 0 1-1-1v-1H7a1 1 0 0 1-1-1V8H4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1h6zm9 16h-4v2h4v-2zm0-8h-4v2h4v-2zM9 4H5v2h4V4z"/>
</svg>

After

Width:  |  Height:  |  Size: 449 B

6
scripts/assets/yaml.svg Normal file
View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 512 470.647">
<polygon points="235.793 0 143.978 137.674 143.978 224.949 87.702 224.949 87.702 137.674 0 0 63.25 0 119.018 88.646 175.243 0 235.793 0 235.793 0"/>
<path d="M330.294,175.451h-101.861l-20.717,50.024h-45.106l95.38,-224.949h46.137l91.51,224.949h-48.2l-17.144,-50.024zm-16.92,-44.911l-31.226,-82.55l-34.837,82.55h66.063z"/>
<polygon points="87.701 250.177 87.701 470.647 135.004 470.647 135.004 318.569 184.509 420.789 221.743 420.789 272.939 314.976 272.939 470.602 318.318 470.602 318.318 250.177 256.358 250.177 201.381 349.883 149.021 250.177 87.701 250.177 87.701 250.177"/>
<polygon points="512 422.735 395.638 422.735 395.638 250.125 347.442 250.125 347.442 469.647 512 469.647 512 422.737 512 422.735"/>
</svg>

After

Width:  |  Height:  |  Size: 810 B

View File

@ -203,8 +203,7 @@ table td:first-child>code {
--text-opacity: 1;
color: rgb(5 150 105/var(--text-opacity));
}
table td:first-child>del>code {
text-decoration: inherit;
table td > del, table td:first-child > del > code, .wrap-body p > del > code {
color: var(--color-danger-fg);
}
@ -293,21 +292,34 @@ body.home .h1wrap p {
grid-template-columns: repeat(2,minmax(0,1fr));
}
[data-color-mode*='light'] body .home-card a {
--text-opacity: 0.75;
color: rgb(15 19 24/var(--text-opacity));
}
[data-color-mode*='light'] body .home-card a:hover {
--text-opacity: 0.85;
color: rgb(241 245 249/var(--text-opacity)) !important;
}
.home-card a {
display: flex;
align-items: center;
gap: 0.5rem;
cursor: pointer;
border-radius: 0.5rem;
padding: 1rem;
padding: 0rem 1rem;
height: 4rem;
box-shadow: 0 0 #0000,0 0 #0000,0 1px 2px 0 rgba(0,0,0,0.05);
color: var(--color-fg-default);
--text-opacity: 0.75;
color: rgb(241 245 249/var(--text-opacity));
--bg-opacity: 0.5;
background-color: rgb(62 69 72/var(--bg-opacity));
transition: all .3s;
text-decoration: none;
}
.home-card a:hover {
--bg-opacity: 1;
--text-opacity: 0.75;
}
.home-card a svg {
min-width: 1.6rem;
@ -576,6 +588,55 @@ body:not(.home) .h2wrap > h2 a::after {
position: relative;
}
.h2wrap-body ul.style-timeline {
counter-reset: stepCount;
}
.h2wrap-body ul.style-timeline li:first-child:before {
background-color: #228e6c;
color: rgb(226 232 240/1);
}
.h2wrap-body ul.style-timeline li::before {
color: #228e6c;
background-color: #fff;
counter-increment: stepCount;
content: counter(stepCount);
border-radius: initial;
border-radius: 0.5rem;
height: 1.5rem;
width: 1.5rem;
text-align: center;
font-size: 0.875rem;
line-height: 1.30rem;
border: 2px solid #228e6c;
top: -1px;
left: -14px;
}
.h2wrap-body ul.style-timeline li:last-child {
border-image: linear-gradient(to bottom,#228e6c,rgba(0,0,0,0)) 1 100%;
}
.h2wrap-body ul.style-timeline li {
border-bottom: 0 !important;
padding-top: 0 !important;
padding-bottom: 25px !important;
border-left: 2px solid #228e6c;
margin-left: 30px;
}
.h2wrap-body ul.style-timeline li > pre {
padding: 0 !important;
padding-top: 10px !important;
height: initial !important;
}
.h2wrap-body ul.style-round li::before {
border-radius: 9999px;
border-width: 2px;
height: 0.5rem;
width: 0.5rem;
border-color: #228e6c;
background: transparent;
top: 14px;
}
.wrap-body ul:last-child {
margin-bottom: 0;
}
@ -629,6 +690,9 @@ body:not(.home) .h2wrap > h2 a::after {
.cols-5 {
grid-template-columns: repeat(5,minmax(0,1fr)) !important;
}
.cols-6 {
grid-template-columns: repeat(6,minmax(0,1fr)) !important;
}
.col-span-2 {
grid-column: span 2/span 2;
}
@ -795,13 +859,7 @@ body:not(.home) .h2wrap > h2 a::after {
}
}
@media (min-width: 768px) {
.home-card {
grid-template-columns: repeat(4,minmax(0,1fr));
}
}
@media (min-width: 375px) {
@media only screen and (max-width: 375px) {
.header-nav .title {
font-size: 1rem;
}
@ -825,6 +883,9 @@ body:not(.home) .h2wrap > h2 a::after {
.wrap-header.h3wrap > .wrap-body {
overflow: auto;
}
.tooltip:hover .tooltiptext {
display: none;
}
.h1wrap-body {
gap: 2rem;
}
@ -841,4 +902,23 @@ body:not(.home) .h2wrap > h2 a::after {
.footer-wrap {
font-size: 0.75rem;
}
table td, table th {
display: block;
text-align: left !important;
}
table td + td, table th + th {
padding-top: 0 !important;
}
}
@media (min-width: 768px) {
.home-card {
grid-template-columns: repeat(4,minmax(0,1fr));
}
.wrap-header.h3wrap > .wrap-body {
overflow: initial;
}
.tooltip:hover .tooltiptext {
display: inline-block;
}
}