Compare commits
No commits in common. "master" and "v5.15.16" have entirely different histories.
@ -4,6 +4,3 @@ dist
|
|||||||
.history
|
.history
|
||||||
images
|
images
|
||||||
docs
|
docs
|
||||||
Dockerfile
|
|
||||||
README.md
|
|
||||||
build.sh
|
|
||||||
|
52
README.md
@ -5,7 +5,7 @@ StackEdit中文版
|
|||||||
</h1>
|
</h1>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<strong>笔记利器,在线Markdown编辑器。</strong><br>
|
<strong>笔记利器,在线Markdown编辑器。</strong><br>
|
||||||
项目clone自<a href="https://gitee.com/mafgwo/stackedit" target="_blank" title="豆萁">豆萁/stackedit</a>,如果你喜欢该项目,请过去点一下Star,您的肯定是作者最大的动力!
|
如果你喜欢该项目,请点一下Star,您的肯定是作者最大的动力!
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://stackedit.cn/">https://stackedit.cn</a>
|
<a href="https://stackedit.cn/">https://stackedit.cn</a>
|
||||||
@ -22,19 +22,18 @@ StackEdit中文版
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<br/>
|
<br/>
|
||||||
|
<p align="center">
|
||||||
|
<a target="_blank" href="https://jq.qq.com/?_wv=1027&k=wUSCNqmN">
|
||||||
|
<img src="https://img.shields.io/badge/QQ交流群-703187410-orange"/></a>
|
||||||
|
</p>
|
||||||
<hr />
|
<hr />
|
||||||
1 笔记支持Gitee、GitHub、Gitea等Git仓库存储。<br>
|
1 笔记支持Gitee、GitHub、Gitea等Git仓库存储。<br>
|
||||||
2 支持直接上传图片,也支持多种外部图床(GitHub、Gitea、SM.MS、自定义图床)粘贴或拖拽上传。<br>
|
2 支持直接上传图片,也支持多种外部图床(GitHub、Gitea、SM.MS、自定义图床)粘贴或拖拽上传。<br>
|
||||||
3 编辑区域支持选择主题或自定义,总有你喜欢的主题。<br>
|
3 编辑区域支持选择主题或自定义,总有你喜欢的主题。<br>
|
||||||
4 支持历史版本管理,不用担心编辑覆盖后无法回滚。<br>
|
4 支持历史版本管理,不用担心编辑覆盖后无法回滚。<br>
|
||||||
5 支持ChatGPT辅助写作。<br>
|
5 支持KaTeX数学表达式、Mermaid UML图、乐谱等扩展。
|
||||||
6 支持KaTeX数学表达式、Mermaid UML图、乐谱等扩展。
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
## 说明
|
|
||||||
|
|
||||||
本项目为本人clone修改自用,如果你也喜欢,请至原作者处获取及交流。
|
|
||||||
|
|
||||||
## 截图
|
## 截图
|
||||||
|
|
||||||
**亮暗主题切换、编辑主题切换**
|
**亮暗主题切换、编辑主题切换**
|
||||||
@ -49,11 +48,7 @@ StackEdit中文版
|
|||||||
**支持文档搜索**
|
**支持文档搜索**
|
||||||

|

|
||||||
|
|
||||||
**ChatGPT集成协助写作**
|
|
||||||

|
|
||||||
|
|
||||||
## 相比国外开源版本的区别:
|
## 相比国外开源版本的区别:
|
||||||
|
|
||||||
- 修复了Github授权登录问题
|
- 修复了Github授权登录问题
|
||||||
- 支持了Gitee仓库(2022-05-25)
|
- 支持了Gitee仓库(2022-05-25)
|
||||||
- 支持了Gitea仓库(2022-05-25)
|
- 支持了Gitea仓库(2022-05-25)
|
||||||
@ -73,26 +68,16 @@ StackEdit中文版
|
|||||||
- 支持编辑区域选择主题样式(2022-10-06)
|
- 支持编辑区域选择主题样式(2022-10-06)
|
||||||
- 支持图片直接存储到当前文档空间(2022-10-29)
|
- 支持图片直接存储到当前文档空间(2022-10-29)
|
||||||
- 支持MD文档之间链接跳转(2022-11-20)
|
- 支持MD文档之间链接跳转(2022-11-20)
|
||||||
- 支持预览区域选择主题样式(2022-12-04)
|
|
||||||
- Gitlab的支持优化(2023-02-23)
|
|
||||||
- 导出HTML、PDF支持带预览主题导出(2023-02-26)
|
|
||||||
- 支持分享文档(2023-03-30)
|
|
||||||
- 支持ChatGPT生成内容(2023-04-10)
|
|
||||||
- GitLab授权接口调整(2023-08-26)
|
|
||||||
- 主文档空间支持GitHub登录(2023-10-19)
|
|
||||||
|
|
||||||
## 国外开源版本弊端:
|
## 国外开源版本弊端:
|
||||||
|
- 作者已经不维护了
|
||||||
- 作者已经不维护了或很少维护了
|
- Github授权登录存在问题
|
||||||
- 不支持国内常用Gitee
|
- 不支持国内常用Gitee
|
||||||
- 强依赖GoogleDrive,而Google Drive在国内不能正常访问
|
- 强依赖GoogleDrive,而Google Drive在国内不能正常访问
|
||||||
|
|
||||||
## 部署说明
|
## 部署说明
|
||||||
|
|
||||||
> 建议docker-compose方式部署,其他部署方式如遇到问题欢迎提issue。
|
> 建议docker-compose方式部署,其他部署方式如遇到问题欢迎提issue。
|
||||||
|
|
||||||
docker官方仓库下载太慢可以使用阿里云的镜像仓库,镜像仓库地址:registry.cn-hangzhou.aliyuncs.com/mafgwo/stackedit:【版本号】
|
|
||||||
|
|
||||||
`docker-compose.yml`如下:
|
`docker-compose.yml`如下:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@ -116,9 +101,6 @@ services:
|
|||||||
- GITEA_CLIENT_ID=【不需要支持则删掉】
|
- GITEA_CLIENT_ID=【不需要支持则删掉】
|
||||||
- GITEA_CLIENT_SECRET=【不需要支持则删掉】
|
- GITEA_CLIENT_SECRET=【不需要支持则删掉】
|
||||||
- GITEA_URL=【不需要支持则删掉】
|
- GITEA_URL=【不需要支持则删掉】
|
||||||
- GITLAB_CLIENT_ID=【不需要支持则删掉】
|
|
||||||
- GITLAB_CLIENT_SECRET=【不需要支持则删掉】
|
|
||||||
- GITLAB_URL=【不需要支持则删掉】
|
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080/tcp
|
- 8080:8080/tcp
|
||||||
network_mode: bridge
|
network_mode: bridge
|
||||||
@ -126,7 +108,6 @@ services:
|
|||||||
```
|
```
|
||||||
|
|
||||||
docker-compose方式的启动或停止命令
|
docker-compose方式的启动或停止命令
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 在 docker-compose.yml 文件目录下 启动命令
|
# 在 docker-compose.yml 文件目录下 启动命令
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
@ -154,26 +135,21 @@ docker run -itd --name stackedit \
|
|||||||
-e GITEA_CLIENT_ID=【不需要支持则删掉】 \
|
-e GITEA_CLIENT_ID=【不需要支持则删掉】 \
|
||||||
-e GITEA_CLIENT_SECRET=【不需要支持则删掉】 \
|
-e GITEA_CLIENT_SECRET=【不需要支持则删掉】 \
|
||||||
-e GITEA_URL=【不需要支持则删掉】 \
|
-e GITEA_URL=【不需要支持则删掉】 \
|
||||||
-e GITLAB_CLIENT_ID=【不需要支持则删掉】 \
|
|
||||||
-e GITLAB_CLIENT_SECRET=【不需要支持则删掉】 \
|
|
||||||
-e GITLAB_URL=【不需要支持则删掉】 \
|
|
||||||
mafgwo/stackedit:【docker中央仓库找到最新版本】
|
mafgwo/stackedit:【docker中央仓库找到最新版本】
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 如何创建三方平台应用
|
## 如何创建三方平台应用
|
||||||
|
|
||||||
> 部署时,如果需要支持Gitee或GitHub,则需要自行到对应三方平台创建应用,获取到应用ID和秘钥,替换到以上的环境变量中,再启动应用。
|
> 部署时,如果需要支持Gitee或GitHub,则需要自行到对应三方平台创建应用,获取到应用ID和秘钥,替换到以上的环境变量中,再启动应用。
|
||||||
|
|
||||||
- Gitee的环境变量:GITEE_CLIENT_ID、GITEE_CLIENT_SECRET,**[如何创建Gitee应用](./docs/部署之Gitee应用创建.md)**
|
- Gitee的环境变量:GITEE_CLIENT_ID、GITEE_CLIENT_SECRET,**[如何创建Gitee应用](./docs/部署之Gitee应用创建.md)**
|
||||||
- GitHub的环境变量:GITHUB_CLIENT_ID、GITEE_CLIENT_SECRET,**[如何创建GitHub应用](./docs/部署之GitHub应用创建.md)**
|
|
||||||
- Gitea可选择性配置环境变量(未配置则在关联时前端指定,有配置则仅允许配置的应用信息):GITEA_CLIENT_ID、GITEA_CLIENT_SECRET、GITEA_URL,**[如何创建Gitea应用](./docs/部署之Gitea应用创建.md)**
|
|
||||||
- Gitlab可选择性配置环境变量(未配置则在关联时前端指定,有配置则仅允许配置的应用信息):GITLAB_CLIENT_ID、GITLAB_CLIENT_SECRET、GITLAB_URL **如何创建Gitlab应用(待补充文档)**
|
|
||||||
|
|
||||||
(特别说明:自建的Gitea、Gitlab要能接入stackedit必须支持跨域)
|
- GitHub的环境变量:GITHUB_CLIENT_ID、GITEE_CLIENT_SECRET,**[如何创建GitHub应用](./docs/部署之GitHub应用创建.md)**
|
||||||
|
|
||||||
|
- Gitea可选择性配置环境变量(未配置则在关联时前端指定,有配置则仅允许配置的应用信息):GITEA_CLIENT_ID、GITEA_CLIENT_SECRET、GITEA_URL,**[如何创建Gitea应用](./docs/部署之Gitea应用创建.md)**
|
||||||
|
|
||||||
|
|
||||||
## 编译与运行
|
## 编译与运行
|
||||||
|
|
||||||
> 编译运行的nodejs版本选择11.15.0版本
|
> 编译运行的nodejs版本选择11.15.0版本
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@ -189,3 +165,7 @@ npm run build
|
|||||||
# build for production and view the bundle analyzer report
|
# build for production and view the bundle analyzer report
|
||||||
npm run build --report
|
npm run build --report
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 欢迎加群交流
|
||||||
|
关于StackEdit,如果你有想法,或者使用中遇到了问题,可以提Issue,如果需要快速得到反馈,可以加QQ群如下(加群后可直接@群主):
|
||||||
|

|
||||||
|
37
build.sh
@ -1,37 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 检查参数是否提供版本号
|
|
||||||
if [ -z "$1" ]; then
|
|
||||||
echo "请提供版本号作为参数"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 定义版本号变量
|
|
||||||
VERSION="$1"
|
|
||||||
IMAGE_NAME="mafgwo/stackedit"
|
|
||||||
|
|
||||||
# 构建 Docker 镜像
|
|
||||||
build_image() {
|
|
||||||
docker build -t "$IMAGE_NAME" .
|
|
||||||
}
|
|
||||||
|
|
||||||
# 标记 Docker 镜像
|
|
||||||
tag_image() {
|
|
||||||
docker tag "$IMAGE_NAME" "$IMAGE_NAME:$VERSION"
|
|
||||||
docker tag "$IMAGE_NAME" "registry.cn-hangzhou.aliyuncs.com/$IMAGE_NAME:$VERSION"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 推送 Docker 镜像
|
|
||||||
push_image() {
|
|
||||||
docker push "$IMAGE_NAME"
|
|
||||||
docker push "registry.cn-hangzhou.aliyuncs.com/$IMAGE_NAME"
|
|
||||||
docker push "$IMAGE_NAME:$VERSION"
|
|
||||||
docker push "registry.cn-hangzhou.aliyuncs.com/$IMAGE_NAME:$VERSION"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 执行构建、标记和推送
|
|
||||||
build_image
|
|
||||||
tag_image
|
|
||||||
push_image
|
|
||||||
|
|
||||||
echo "操作完成"
|
|
@ -18,8 +18,6 @@ awsSecretAccessKey: ""
|
|||||||
giteaClientId: ""
|
giteaClientId: ""
|
||||||
giteaClientSecret: ""
|
giteaClientSecret: ""
|
||||||
giteaUrl: ""
|
giteaUrl: ""
|
||||||
gitlabClientId: ""
|
|
||||||
gitlabUrl: ""
|
|
||||||
|
|
||||||
replicaCount: 1
|
replicaCount: 1
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 491 B |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 960 B |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 1.9 KiB |
@ -1,28 +1,28 @@
|
|||||||
{
|
{
|
||||||
"name": "StackEdit中文版",
|
"name": "StackEdit中文版",
|
||||||
"description": "支持Gitee仓库/粘贴图片自动上传的浏览器内 Markdown 编辑器",
|
"description": "支持Gitee仓库/粘贴图片自动上传的浏览器内 Markdown 编辑器",
|
||||||
"version": "5.15.17",
|
"version": "5.15.16",
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"container": "GITEE",
|
"container" : "GITEE",
|
||||||
"api_console_project_id": "241271498917",
|
"api_console_project_id" : "241271498917",
|
||||||
"icons": {
|
"icons": {
|
||||||
"16": "icon-16.png",
|
"16": "icon-16.png",
|
||||||
"32": "icon-32.png",
|
"32": "icon-32.png",
|
||||||
"64": "icon-64.png",
|
"64": "icon-64.png",
|
||||||
"128": "icon-128.png",
|
"128": "icon-128.png",
|
||||||
"256": "icon-256.png",
|
"256": "icon-256.png",
|
||||||
"512": "icon-512.png"
|
"512": "icon-512.png"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"urls": [
|
"urls": [
|
||||||
"https://md.jonylee.top/"
|
"https://stackedit.cn/"
|
||||||
],
|
],
|
||||||
"launch": {
|
"launch": {
|
||||||
"web_url": "https://md.jonylee.top/app"
|
"web_url": "https://stackedit.cn/app"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"offline_enabled": true,
|
"offline_enabled": true,
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"unlimitedStorage"
|
"unlimitedStorage"
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -12,7 +12,4 @@ module.exports = merge(prodEnv, {
|
|||||||
// GITEA_CLIENT_ID: '"fe30f8f9-b1e8-4531-8f72-c1a5d3912805"',
|
// GITEA_CLIENT_ID: '"fe30f8f9-b1e8-4531-8f72-c1a5d3912805"',
|
||||||
// GITEA_CLIENT_SECRET: '"lus7oMnb3H6M1hsChndphArE20Txr7erwJLf7SDBQWTw"',
|
// GITEA_CLIENT_SECRET: '"lus7oMnb3H6M1hsChndphArE20Txr7erwJLf7SDBQWTw"',
|
||||||
// GITEA_URL: '"https://gitea.test.com"',
|
// GITEA_URL: '"https://gitea.test.com"',
|
||||||
GITLAB_CLIENT_ID: '"074cd5103c62dea0f479dac861039656ac80935e304c8113a02cc64c629496ae"',
|
|
||||||
GITLAB_CLIENT_SECRET: '"6f406f24216b686d55d28313dec1913c2a8e599afdb08380d5e8ce838e16e41e"',
|
|
||||||
GITLAB_URL: '"http://gitlab.qicoder.com"',
|
|
||||||
})
|
})
|
@ -1,10 +0,0 @@
|
|||||||
# 大文档导出PDF方式说明
|
|
||||||
> 由于大文档导出PDF,需要消费非常多的服务器资源,而且很容易导致导出超时,故导出PDF的MD文档过大时,可以使用 **[wkhtmltopdf](https://wkhtmltopdf.org/downloads.html)** 工具导出。
|
|
||||||
|
|
||||||
# 操作步骤
|
|
||||||
- 先在 **[StackEdit中文版](https://stackedit.cn/app)** 中使用 `导出为HTML` 功能导出MD文档,导出后可以得到一个HTML文档。
|
|
||||||
- 到 **[wkhtmltopdf](https://wkhtmltopdf.org/downloads.html)** 官网下载安装程序。
|
|
||||||
- 使用 wkhtmltopdf 的导出PDF的命令 `wkhtmltopdf [GLOBAL OPTION]... [OBJECT]... <output file>` 把HTML导出为PDF,如简单的导出命令:`wkhtmltopdf test.html test.pdf`,具体的 `GLOBAL OPTION` 参数说明可以通过 `wkhtmltopdf -H` 查看帮助文档。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 175 KiB |
35
index.html
@ -1,31 +1,28 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Markdown编辑器-JonyLee的设计导航</title>
|
<title>StackEdit中文版</title>
|
||||||
<link rel="canonical" href="https://md.jonylee.top">
|
<link rel="canonical" href="https://stackedit.cn/app">
|
||||||
<meta name="description" content="StackEdit中文版,免费,开源,功能全面的Markdown编辑器。">
|
<meta name="description" content="免费,开源,功能全面的Markdown编辑器。">
|
||||||
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
</head>
|
<script>
|
||||||
|
var _hmt = _hmt || [];
|
||||||
<body>
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<!-- built files will be auto injected -->
|
<!-- built files will be auto injected -->
|
||||||
<!-- baidu统计 -->
|
|
||||||
<script>
|
<script>
|
||||||
var _hmt = _hmt || [];
|
(function() {
|
||||||
(function() {
|
var hm = document.createElement("script");
|
||||||
var hm = document.createElement("script");
|
hm.src = "https://hm.baidu.com/hm.js?20a1e7a201b42702c49074c87a1f1035";
|
||||||
hm.src = "https://hm.baidu.com/hm.js?dad4b4383b13eedea1ab45ee323df1c3";
|
var s = document.getElementsByTagName("script")[0];
|
||||||
var s = document.getElementsByTagName("script")[0];
|
s.parentNode.insertBefore(hm, s);
|
||||||
s.parentNode.insertBefore(hm, s);
|
})();
|
||||||
})();
|
|
||||||
</script>
|
</script>
|
||||||
<!-- baidu统计结束 -->
|
</body>
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
</html>
|
122
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stackedit",
|
"name": "stackedit",
|
||||||
"version": "5.15.21",
|
"version": "5.15.16",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1278,6 +1278,38 @@
|
|||||||
"postcss-value-parser": "^3.2.3"
|
"postcss-value-parser": "^3.2.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"aws-sdk": {
|
||||||
|
"version": "2.317.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.317.0.tgz",
|
||||||
|
"integrity": "sha512-X2Cd1Gb9Cf9WVgGOiBSW4TK6q5Mb6AYiGmEA9XikCgur4H8E4TgmgWbBWJnTzxssugclVLVoWQfw3RshNKJksg==",
|
||||||
|
"requires": {
|
||||||
|
"buffer": "4.9.1",
|
||||||
|
"events": "1.1.1",
|
||||||
|
"ieee754": "1.1.8",
|
||||||
|
"jmespath": "0.15.0",
|
||||||
|
"querystring": "0.2.0",
|
||||||
|
"sax": "1.2.1",
|
||||||
|
"url": "0.10.3",
|
||||||
|
"uuid": "3.1.0",
|
||||||
|
"xml2js": "0.4.19"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"xml2js": {
|
||||||
|
"version": "0.4.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
|
||||||
|
"integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
|
||||||
|
"requires": {
|
||||||
|
"sax": ">=0.6.0",
|
||||||
|
"xmlbuilder": "~9.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xmlbuilder": {
|
||||||
|
"version": "9.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
|
||||||
|
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"aws-sign2": {
|
"aws-sign2": {
|
||||||
"version": "0.7.0",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||||
@ -2319,8 +2351,7 @@
|
|||||||
"base64-js": {
|
"base64-js": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
|
||||||
"integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==",
|
"integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"bcrypt-pbkdf": {
|
"bcrypt-pbkdf": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@ -2568,7 +2599,6 @@
|
|||||||
"version": "4.9.1",
|
"version": "4.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
|
||||||
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
|
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"base64-js": "^1.0.2",
|
"base64-js": "^1.0.2",
|
||||||
"ieee754": "^1.1.4",
|
"ieee754": "^1.1.4",
|
||||||
@ -3988,7 +4018,7 @@
|
|||||||
},
|
},
|
||||||
"d3-collection": {
|
"d3-collection": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmmirror.com/d3-collection/-/d3-collection-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz",
|
||||||
"integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
|
"integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
|
||||||
},
|
},
|
||||||
"d3-color": {
|
"d3-color": {
|
||||||
@ -4166,7 +4196,7 @@
|
|||||||
},
|
},
|
||||||
"d3-voronoi": {
|
"d3-voronoi": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmmirror.com/d3-voronoi/-/d3-voronoi-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz",
|
||||||
"integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg=="
|
"integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg=="
|
||||||
},
|
},
|
||||||
"d3-zoom": {
|
"d3-zoom": {
|
||||||
@ -4183,7 +4213,7 @@
|
|||||||
},
|
},
|
||||||
"dagre": {
|
"dagre": {
|
||||||
"version": "0.8.5",
|
"version": "0.8.5",
|
||||||
"resolved": "https://registry.npmmirror.com/dagre/-/dagre-0.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
|
||||||
"integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==",
|
"integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"graphlib": "^2.1.8",
|
"graphlib": "^2.1.8",
|
||||||
@ -4192,14 +4222,14 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dagre-d3": {
|
"dagre-d3": {
|
||||||
"version": "0.6.4",
|
"version": "0.6.4",
|
||||||
"resolved": "https://registry.npmmirror.com/dagre-d3/-/dagre-d3-0.6.4.tgz",
|
"resolved": "https://registry.npmjs.org/dagre-d3/-/dagre-d3-0.6.4.tgz",
|
||||||
"integrity": "sha512-e/6jXeCP7/ptlAM48clmX4xTZc5Ek6T6kagS7Oz2HrYSdqcLZFLqpAfh7ldbZRFfxCZVyh61NEPR08UQRVxJzQ==",
|
"integrity": "sha512-e/6jXeCP7/ptlAM48clmX4xTZc5Ek6T6kagS7Oz2HrYSdqcLZFLqpAfh7ldbZRFfxCZVyh61NEPR08UQRVxJzQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"d3": "^5.14",
|
"d3": "^5.14",
|
||||||
@ -4210,7 +4240,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4746,7 +4776,7 @@
|
|||||||
},
|
},
|
||||||
"entity-decode": {
|
"entity-decode": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmmirror.com/entity-decode/-/entity-decode-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/entity-decode/-/entity-decode-2.0.2.tgz",
|
||||||
"integrity": "sha512-5CCY/3ci4MC1m2jlumNjWd7VBFt4VfFnmSqSNmVcXq4gxM3Vmarxtt+SvmBnzwLS669MWdVuXboNVj1qN2esVg==",
|
"integrity": "sha512-5CCY/3ci4MC1m2jlumNjWd7VBFt4VfFnmSqSNmVcXq4gxM3Vmarxtt+SvmBnzwLS669MWdVuXboNVj1qN2esVg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"he": "^1.1.1"
|
"he": "^1.1.1"
|
||||||
@ -5362,8 +5392,7 @@
|
|||||||
"events": {
|
"events": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
|
||||||
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
|
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"eventsource-polyfill": {
|
"eventsource-polyfill": {
|
||||||
"version": "0.9.6",
|
"version": "0.9.6",
|
||||||
@ -8636,6 +8665,16 @@
|
|||||||
"delegate": "^3.1.2"
|
"delegate": "^3.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"google-id-token-verifier": {
|
||||||
|
"version": "0.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/google-id-token-verifier/-/google-id-token-verifier-0.2.3.tgz",
|
||||||
|
"integrity": "sha1-nmt41FieLQUNqBYT+4kK26MKTqg=",
|
||||||
|
"requires": {
|
||||||
|
"request": "^2.65.0",
|
||||||
|
"rsa-pem-from-mod-exp": "^0.8.4",
|
||||||
|
"underscore": "^1.8.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"graceful-fs": {
|
"graceful-fs": {
|
||||||
"version": "4.1.11",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
|
||||||
@ -8644,7 +8683,7 @@
|
|||||||
},
|
},
|
||||||
"graphlib": {
|
"graphlib": {
|
||||||
"version": "2.1.8",
|
"version": "2.1.8",
|
||||||
"resolved": "https://registry.npmmirror.com/graphlib/-/graphlib-2.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz",
|
||||||
"integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==",
|
"integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lodash": "^4.17.15"
|
"lodash": "^4.17.15"
|
||||||
@ -8652,7 +8691,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9624,8 +9663,7 @@
|
|||||||
"ieee754": {
|
"ieee754": {
|
||||||
"version": "1.1.8",
|
"version": "1.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
|
||||||
"integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=",
|
"integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"iferr": {
|
"iferr": {
|
||||||
"version": "0.1.5",
|
"version": "0.1.5",
|
||||||
@ -11224,6 +11262,11 @@
|
|||||||
"url-regex": "^3.0.0"
|
"url-regex": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jmespath": {
|
||||||
|
"version": "0.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
|
||||||
|
"integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
|
||||||
|
},
|
||||||
"jpeg-js": {
|
"jpeg-js": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz",
|
||||||
@ -12501,7 +12544,7 @@
|
|||||||
},
|
},
|
||||||
"minify": {
|
"minify": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmmirror.com/minify/-/minify-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/minify/-/minify-4.1.3.tgz",
|
||||||
"integrity": "sha512-ykuscavxivSmVpcCzsXmsVTukWYLUUtPhHj0w2ILvHDGqC+hsuTCihBn9+PJBd58JNvWTNg9132J9nrrI2anzA==",
|
"integrity": "sha512-ykuscavxivSmVpcCzsXmsVTukWYLUUtPhHj0w2ILvHDGqC+hsuTCihBn9+PJBd58JNvWTNg9132J9nrrI2anzA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"clean-css": "^4.1.6",
|
"clean-css": "^4.1.6",
|
||||||
@ -12515,7 +12558,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": {
|
"commander": {
|
||||||
"version": "2.20.3",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
@ -12528,12 +12571,12 @@
|
|||||||
},
|
},
|
||||||
"he": {
|
"he": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmmirror.com/he/-/he-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
||||||
},
|
},
|
||||||
"html-minifier": {
|
"html-minifier": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/html-minifier/-/html-minifier-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz",
|
||||||
"integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==",
|
"integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"camel-case": "^3.0.0",
|
"camel-case": "^3.0.0",
|
||||||
@ -12547,7 +12590,7 @@
|
|||||||
},
|
},
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
},
|
},
|
||||||
"uglify-js": {
|
"uglify-js": {
|
||||||
@ -15269,8 +15312,7 @@
|
|||||||
"punycode": {
|
"punycode": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
|
||||||
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
|
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"q": {
|
"q": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
@ -15296,8 +15338,7 @@
|
|||||||
"querystring": {
|
"querystring": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||||
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
|
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"querystring-es3": {
|
"querystring-es3": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
@ -16417,6 +16458,11 @@
|
|||||||
"inherits": "^2.0.1"
|
"inherits": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rsa-pem-from-mod-exp": {
|
||||||
|
"version": "0.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/rsa-pem-from-mod-exp/-/rsa-pem-from-mod-exp-0.8.4.tgz",
|
||||||
|
"integrity": "sha1-NipCxtMEBW1JOz8SvOq7LGV2ptQ="
|
||||||
|
},
|
||||||
"rsvp": {
|
"rsvp": {
|
||||||
"version": "3.6.2",
|
"version": "3.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz",
|
||||||
@ -17707,8 +17753,7 @@
|
|||||||
"sax": {
|
"sax": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
|
||||||
"integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=",
|
"integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"schema-utils": {
|
"schema-utils": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
@ -20413,12 +20458,12 @@
|
|||||||
},
|
},
|
||||||
"try-catch": {
|
"try-catch": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/try-catch/-/try-catch-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/try-catch/-/try-catch-2.0.1.tgz",
|
||||||
"integrity": "sha512-LsOrmObN/2WdM+y2xG+t16vhYrQsnV8wftXIcIOWZhQcBJvKGYuamJGwnU98A7Jxs2oZNkJztXlphEOoA0DWqg=="
|
"integrity": "sha512-LsOrmObN/2WdM+y2xG+t16vhYrQsnV8wftXIcIOWZhQcBJvKGYuamJGwnU98A7Jxs2oZNkJztXlphEOoA0DWqg=="
|
||||||
},
|
},
|
||||||
"try-to-catch": {
|
"try-to-catch": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/try-to-catch/-/try-to-catch-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/try-to-catch/-/try-to-catch-1.1.1.tgz",
|
||||||
"integrity": "sha512-ikUlS+/BcImLhNYyIgZcEmq4byc31QpC+46/6Jm5ECWkVFhf8SM2Fp/0pMVXPX6vk45SMCwrP4Taxucne8I0VA=="
|
"integrity": "sha512-ikUlS+/BcImLhNYyIgZcEmq4byc31QpC+46/6Jm5ECWkVFhf8SM2Fp/0pMVXPX6vk45SMCwrP4Taxucne8I0VA=="
|
||||||
},
|
},
|
||||||
"tryer": {
|
"tryer": {
|
||||||
@ -20565,8 +20610,7 @@
|
|||||||
"underscore": {
|
"underscore": {
|
||||||
"version": "1.8.3",
|
"version": "1.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
|
||||||
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
|
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"undertaker": {
|
"undertaker": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
@ -20841,6 +20885,15 @@
|
|||||||
"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
|
"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"url": {
|
||||||
|
"version": "0.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
|
||||||
|
"integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=",
|
||||||
|
"requires": {
|
||||||
|
"punycode": "1.3.2",
|
||||||
|
"querystring": "0.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"url-loader": {
|
"url-loader": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.1.tgz",
|
||||||
@ -20965,6 +21018,11 @@
|
|||||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
|
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"uuid": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
|
||||||
|
},
|
||||||
"v8flags": {
|
"v8flags": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stackedit",
|
"name": "stackedit",
|
||||||
"version": "5.15.21",
|
"version": "5.15.16",
|
||||||
"description": "免费, 开源, 功能齐全的 Markdown 编辑器",
|
"description": "免费, 开源, 功能齐全的 Markdown 编辑器",
|
||||||
"author": "Benoit Schweblin, 豆萁",
|
"author": "Benoit Schweblin, 豆萁",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
@ -27,6 +27,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/test-utils": "^1.0.0-beta.16",
|
"@vue/test-utils": "^1.0.0-beta.16",
|
||||||
"abcjs": "^5.2.0",
|
"abcjs": "^5.2.0",
|
||||||
|
"aws-sdk": "^2.317.0",
|
||||||
"babel-runtime": "^6.26.0",
|
"babel-runtime": "^6.26.0",
|
||||||
"bezier-easing": "^1.1.0",
|
"bezier-easing": "^1.1.0",
|
||||||
"body-parser": "^1.18.2",
|
"body-parser": "^1.18.2",
|
||||||
@ -34,6 +35,7 @@
|
|||||||
"compression": "^1.7.0",
|
"compression": "^1.7.0",
|
||||||
"diff-match-patch": "^1.0.0",
|
"diff-match-patch": "^1.0.0",
|
||||||
"file-saver": "^1.3.8",
|
"file-saver": "^1.3.8",
|
||||||
|
"google-id-token-verifier": "^0.2.3",
|
||||||
"handlebars": "^4.0.10",
|
"handlebars": "^4.0.10",
|
||||||
"indexeddbshim": "^3.6.2",
|
"indexeddbshim": "^3.6.2",
|
||||||
"js-yaml": "^3.11.0",
|
"js-yaml": "^3.11.0",
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
const pandocPath = process.env.PANDOC_PATH || 'pandoc';
|
const pandocPath = process.env.PANDOC_PATH || 'pandoc';
|
||||||
const wkhtmltopdfPath = process.env.WKHTMLTOPDF_PATH || 'wkhtmltopdf';
|
const wkhtmltopdfPath = process.env.WKHTMLTOPDF_PATH || 'wkhtmltopdf';
|
||||||
|
const userBucketName = process.env.USER_BUCKET_NAME || 'stackedit-users';
|
||||||
|
const paypalUri = process.env.PAYPAL_URI || 'https://www.paypal.com/cgi-bin/webscr';
|
||||||
const paypalReceiverEmail = process.env.PAYPAL_RECEIVER_EMAIL;
|
const paypalReceiverEmail = process.env.PAYPAL_RECEIVER_EMAIL;
|
||||||
|
|
||||||
const dropboxAppKey = process.env.DROPBOX_APP_KEY;
|
const dropboxAppKey = process.env.DROPBOX_APP_KEY;
|
||||||
@ -14,13 +16,12 @@ const wordpressClientId = process.env.WORDPRESS_CLIENT_ID;
|
|||||||
const giteaClientId = process.env.GITEA_CLIENT_ID;
|
const giteaClientId = process.env.GITEA_CLIENT_ID;
|
||||||
const giteaClientSecret = process.env.GITEA_CLIENT_SECRET;
|
const giteaClientSecret = process.env.GITEA_CLIENT_SECRET;
|
||||||
const giteaUrl = process.env.GITEA_URL;
|
const giteaUrl = process.env.GITEA_URL;
|
||||||
const gitlabClientId = process.env.GITLAB_CLIENT_ID;
|
|
||||||
const gitlabClientSecret = process.env.GITLAB_CLIENT_SECRET;
|
|
||||||
const gitlabUrl = process.env.GITLAB_URL;
|
|
||||||
|
|
||||||
exports.values = {
|
exports.values = {
|
||||||
pandocPath,
|
pandocPath,
|
||||||
wkhtmltopdfPath,
|
wkhtmltopdfPath,
|
||||||
|
userBucketName,
|
||||||
|
paypalUri,
|
||||||
paypalReceiverEmail,
|
paypalReceiverEmail,
|
||||||
dropboxAppKey,
|
dropboxAppKey,
|
||||||
dropboxAppKeyFull,
|
dropboxAppKeyFull,
|
||||||
@ -34,9 +35,6 @@ exports.values = {
|
|||||||
giteaClientId,
|
giteaClientId,
|
||||||
giteaClientSecret,
|
giteaClientSecret,
|
||||||
giteaUrl,
|
giteaUrl,
|
||||||
gitlabClientId,
|
|
||||||
gitlabClientSecret,
|
|
||||||
gitlabUrl,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.publicValues = {
|
exports.publicValues = {
|
||||||
@ -49,6 +47,4 @@ exports.publicValues = {
|
|||||||
allowSponsorship: !!paypalReceiverEmail,
|
allowSponsorship: !!paypalReceiverEmail,
|
||||||
giteaClientId,
|
giteaClientId,
|
||||||
giteaUrl,
|
giteaUrl,
|
||||||
gitlabClientId,
|
|
||||||
gitlabUrl,
|
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
const qs = require('qs');
|
||||||
const request = require('request');
|
const request = require('request');
|
||||||
const conf = require('./conf');
|
const conf = require('./conf');
|
||||||
|
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
const request = require('request');
|
|
||||||
const conf = require('./conf');
|
|
||||||
|
|
||||||
function gitlabToken(queryParam) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
request({
|
|
||||||
method: 'POST',
|
|
||||||
url: `${conf.values.gitlabUrl}/oauth/token`,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
json: true,
|
|
||||||
qs: {
|
|
||||||
...queryParam,
|
|
||||||
client_id: conf.values.gitlabClientId,
|
|
||||||
client_secret: conf.values.gitlabClientSecret,
|
|
||||||
},
|
|
||||||
}, (err, res, body) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
const token = body.access_token;
|
|
||||||
if (token) {
|
|
||||||
resolve(body);
|
|
||||||
} else {
|
|
||||||
reject(res.statusCode + ',body:' + JSON.stringify(body));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.gitlabToken = (req, res) => {
|
|
||||||
gitlabToken(req.query)
|
|
||||||
.then(
|
|
||||||
tokenBody => res.send(tokenBody),
|
|
||||||
err => res
|
|
||||||
.status(400)
|
|
||||||
.send(err ? err.message || err.toString() : 'bad_code'),
|
|
||||||
);
|
|
||||||
};
|
|
@ -2,10 +2,10 @@ const compression = require('compression');
|
|||||||
const serveStatic = require('serve-static');
|
const serveStatic = require('serve-static');
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const user = require('./user');
|
||||||
const github = require('./github');
|
const github = require('./github');
|
||||||
const gitee = require('./gitee');
|
const gitee = require('./gitee');
|
||||||
const gitea = require('./gitea');
|
const gitea = require('./gitea');
|
||||||
const gitlab = require('./gitlab');
|
|
||||||
const pdf = require('./pdf');
|
const pdf = require('./pdf');
|
||||||
const pandoc = require('./pandoc');
|
const pandoc = require('./pandoc');
|
||||||
const conf = require('./conf');
|
const conf = require('./conf');
|
||||||
@ -29,10 +29,13 @@ module.exports = (app) => {
|
|||||||
app.get('/oauth2/githubToken', github.githubToken);
|
app.get('/oauth2/githubToken', github.githubToken);
|
||||||
app.get('/oauth2/giteeToken', gitee.giteeToken);
|
app.get('/oauth2/giteeToken', gitee.giteeToken);
|
||||||
app.get('/oauth2/giteaToken', gitea.giteaToken);
|
app.get('/oauth2/giteaToken', gitea.giteaToken);
|
||||||
app.get('/oauth2/gitlabToken', gitlab.gitlabToken);
|
|
||||||
app.get('/conf', (req, res) => res.send(conf.publicValues));
|
app.get('/conf', (req, res) => res.send(conf.publicValues));
|
||||||
|
app.get('/userInfo', user.userInfo);
|
||||||
app.post('/pdfExport', pdf.generate);
|
app.post('/pdfExport', pdf.generate);
|
||||||
app.post('/pandocExport', pandoc.generate);
|
app.post('/pandocExport', pandoc.generate);
|
||||||
|
app.post('/paypalIpn', bodyParser.urlencoded({
|
||||||
|
extended: false,
|
||||||
|
}), user.paypalIpn);
|
||||||
app.get('/giteeClientId', (req, res) => {
|
app.get('/giteeClientId', (req, res) => {
|
||||||
const giteeClientIds = conf.values.giteeClientId.split(',');
|
const giteeClientIds = conf.values.giteeClientId.split(',');
|
||||||
// 仅一个 则直接返回
|
// 仅一个 则直接返回
|
||||||
@ -63,22 +66,21 @@ module.exports = (app) => {
|
|||||||
res.redirect(`./app#providerId=googleDrive&state=${encodeURIComponent(req.query.state)}`));
|
res.redirect(`./app#providerId=googleDrive&state=${encodeURIComponent(req.query.state)}`));
|
||||||
// Serve the static folder with 30 day max-age
|
// Serve the static folder with 30 day max-age
|
||||||
app.use('/themes', serveStatic(resolvePath('static/themes'), {
|
app.use('/themes', serveStatic(resolvePath('static/themes'), {
|
||||||
maxAge: '5d',
|
maxAge: '30d',
|
||||||
}));
|
}));
|
||||||
|
// Serve empty.js
|
||||||
// Serve style.css with 1 day max-age
|
app.get('/empty.js', (req, res) => res.send(''));
|
||||||
app.get('/style.css', (req, res) => res.sendFile(resolvePath('dist/style.css'), {
|
|
||||||
maxAge: '1d',
|
|
||||||
}));
|
|
||||||
// Serve share.html
|
|
||||||
app.get('/share.html', (req, res) => res.sendFile(resolvePath('static/landing/share.html')));
|
|
||||||
app.get('/gistshare.html', (req, res) => res.sendFile(resolvePath('static/landing/gistshare.html')));
|
|
||||||
|
|
||||||
// Serve static resources
|
// Serve static resources
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
// Serve index.html in /app
|
// Serve index.html in /app
|
||||||
app.get('/app', (req, res) => res.sendFile(resolvePath('dist/index.html')));
|
app.get('/app', (req, res) => res.sendFile(resolvePath('dist/index.html')));
|
||||||
|
|
||||||
|
// Serve style.css with 1 day max-age
|
||||||
|
app.get('/style.css', (req, res) => res.sendFile(resolvePath('dist/style.css'), {
|
||||||
|
maxAge: '1d',
|
||||||
|
}));
|
||||||
|
|
||||||
// Serve the static folder with 1 year max-age
|
// Serve the static folder with 1 year max-age
|
||||||
app.use('/static', serveStatic(resolvePath('dist/static'), {
|
app.use('/static', serveStatic(resolvePath('dist/static'), {
|
||||||
maxAge: '1y',
|
maxAge: '1y',
|
||||||
|
116
server/user.js
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
const request = require('request');
|
||||||
|
const AWS = require('aws-sdk');
|
||||||
|
const verifier = require('google-id-token-verifier');
|
||||||
|
const conf = require('./conf');
|
||||||
|
|
||||||
|
const s3Client = new AWS.S3();
|
||||||
|
|
||||||
|
const cb = (resolve, reject) => (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getUser = id => new Promise((resolve, reject) => {
|
||||||
|
s3Client.getObject({
|
||||||
|
Bucket: conf.values.userBucketName,
|
||||||
|
Key: id,
|
||||||
|
}, cb(resolve, reject));
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
res => JSON.parse(`${res.Body}`),
|
||||||
|
(err) => {
|
||||||
|
if (err.code !== 'NoSuchKey') {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.putUser = (id, user) => new Promise((resolve, reject) => {
|
||||||
|
s3Client.putObject({
|
||||||
|
Bucket: conf.values.userBucketName,
|
||||||
|
Key: id,
|
||||||
|
Body: JSON.stringify(user),
|
||||||
|
}, cb(resolve, reject));
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.removeUser = id => new Promise((resolve, reject) => {
|
||||||
|
s3Client.deleteObject({
|
||||||
|
Bucket: conf.values.userBucketName,
|
||||||
|
Key: id,
|
||||||
|
}, cb(resolve, reject));
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.getUserFromToken = idToken => new Promise((resolve, reject) => verifier
|
||||||
|
.verify(idToken, conf.values.googleClientId, cb(resolve, reject)))
|
||||||
|
.then(tokenInfo => exports.getUser(tokenInfo.sub));
|
||||||
|
|
||||||
|
exports.userInfo = (req, res) => exports.getUserFromToken(req.query.idToken)
|
||||||
|
.then(
|
||||||
|
user => res.send(Object.assign({
|
||||||
|
sponsorUntil: 0,
|
||||||
|
}, user)),
|
||||||
|
err => res
|
||||||
|
.status(400)
|
||||||
|
.send(err ? err.message || err.toString() : 'invalid_token'),
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.paypalIpn = (req, res, next) => Promise.resolve()
|
||||||
|
.then(() => {
|
||||||
|
const userId = req.body.custom;
|
||||||
|
const paypalEmail = req.body.payer_email;
|
||||||
|
const gross = parseFloat(req.body.mc_gross);
|
||||||
|
let sponsorUntil;
|
||||||
|
if (gross === 5) {
|
||||||
|
sponsorUntil = Date.now() + (3 * 31 * 24 * 60 * 60 * 1000); // 3 months
|
||||||
|
} else if (gross === 15) {
|
||||||
|
sponsorUntil = Date.now() + (366 * 24 * 60 * 60 * 1000); // 1 year
|
||||||
|
} else if (gross === 25) {
|
||||||
|
sponsorUntil = Date.now() + (2 * 366 * 24 * 60 * 60 * 1000); // 2 years
|
||||||
|
} else if (gross === 50) {
|
||||||
|
sponsorUntil = Date.now() + (5 * 366 * 24 * 60 * 60 * 1000); // 5 years
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
req.body.receiver_email !== conf.values.paypalReceiverEmail ||
|
||||||
|
req.body.payment_status !== 'Completed' ||
|
||||||
|
req.body.mc_currency !== 'USD' ||
|
||||||
|
(req.body.txn_type !== 'web_accept' && req.body.txn_type !== 'subscr_payment') ||
|
||||||
|
!userId || !sponsorUntil
|
||||||
|
) {
|
||||||
|
// Ignoring PayPal IPN
|
||||||
|
return res.end();
|
||||||
|
}
|
||||||
|
// Processing PayPal IPN
|
||||||
|
req.body.cmd = '_notify-validate';
|
||||||
|
return new Promise((resolve, reject) => request.post({
|
||||||
|
uri: conf.values.paypalUri,
|
||||||
|
form: req.body,
|
||||||
|
}, (err, response, body) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else if (body !== 'VERIFIED') {
|
||||||
|
reject(new Error('PayPal IPN unverified'));
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.then(() => exports.putUser(userId, {
|
||||||
|
paypalEmail,
|
||||||
|
sponsorUntil,
|
||||||
|
}))
|
||||||
|
.then(() => res.end());
|
||||||
|
})
|
||||||
|
.catch(next);
|
||||||
|
|
||||||
|
exports.checkSponsor = (idToken) => {
|
||||||
|
if (!conf.publicValues.allowSponsorship) {
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
if (!idToken) {
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
return exports.getUserFromToken(idToken)
|
||||||
|
.then(userInfo => userInfo && userInfo.sponsorUntil > Date.now(), () => false);
|
||||||
|
};
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 16 KiB |
@ -91,9 +91,6 @@ export default {
|
|||||||
// store 编辑主题
|
// store 编辑主题
|
||||||
const editTheme = localStorage.getItem('theme/currEditTheme');
|
const editTheme = localStorage.getItem('theme/currEditTheme');
|
||||||
store.dispatch('theme/setEditTheme', editTheme || 'default');
|
store.dispatch('theme/setEditTheme', editTheme || 'default');
|
||||||
// store 预览主题
|
|
||||||
const previewTheme = localStorage.getItem('theme/currPreviewTheme');
|
|
||||||
store.dispatch('theme/setPreviewTheme', previewTheme || 'default');
|
|
||||||
this.ready = true;
|
this.ready = true;
|
||||||
tempFileSvc.setReady();
|
tempFileSvc.setReady();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
<icon-select-theme></icon-select-theme>
|
<icon-select-theme></icon-select-theme>
|
||||||
</dropdown-menu>
|
</dropdown-menu>
|
||||||
</li>
|
</li>
|
||||||
<li class="after">
|
<li title="Markdown语法帮助">
|
||||||
<icon-ellipsis></icon-ellipsis>
|
<a @click="showHelp"><icon-help-circle></icon-help-circle></a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -123,6 +123,10 @@ export default {
|
|||||||
store.dispatch('data/setSideBarPanel', 'editTheme');
|
store.dispatch('data/setSideBarPanel', 'editTheme');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
showHelp() {
|
||||||
|
this.toggleSideBar(true);
|
||||||
|
store.dispatch('data/setSideBarPanel', 'help');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@ -133,44 +137,20 @@ export default {
|
|||||||
.editor-in-page-buttons {
|
.editor-in-page-buttons {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: -108px;
|
right: 10px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
background-color: rgba(84, 96, 114, 0.4);
|
background-color: rgba(187, 187, 187, 0.05);
|
||||||
border-radius: $border-radius-base;
|
border-radius: $border-radius-base;
|
||||||
transition: 0.5s;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.dropdown-menu {
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
.dropdown-menu-items {
|
|
||||||
right: unset;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:focus,
|
|
||||||
&:hover {
|
|
||||||
left: 0;
|
|
||||||
transition: 0.5s;
|
|
||||||
background-color: #546072;
|
|
||||||
|
|
||||||
.dropdown-menu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
line-height: 20px;
|
|
||||||
|
|
||||||
li {
|
li {
|
||||||
|
line-height: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
|
||||||
list-style: none;
|
list-style: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@ -180,7 +160,7 @@ export default {
|
|||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
color: #dea731;
|
color: #dea731;
|
||||||
opacity: 0.7;
|
opacity: 0.3;
|
||||||
|
|
||||||
&:active,
|
&:active,
|
||||||
&:focus,
|
&:focus,
|
||||||
@ -188,10 +168,5 @@ export default {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.after {
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: -6px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<explorer-node v-for="node in node.files" :key="node.item.id" :node="node" :depth="depth + 1"></explorer-node>
|
<explorer-node v-for="node in node.files" :key="node.item.id" :node="node" :depth="depth + 1"></explorer-node>
|
||||||
</div>
|
</div>
|
||||||
<button ref="copyId" v-clipboard="copyPath()" @click="info('路径已复制到剪切板!')" style="display: none;"></button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -24,7 +23,6 @@ import workspaceSvc from '../services/workspaceSvc';
|
|||||||
import explorerSvc from '../services/explorerSvc';
|
import explorerSvc from '../services/explorerSvc';
|
||||||
import store from '../store';
|
import store from '../store';
|
||||||
import badgeSvc from '../services/badgeSvc';
|
import badgeSvc from '../services/badgeSvc';
|
||||||
import utils from '../services/utils';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'explorer-node', // Required for recursivity
|
name: 'explorer-node', // Required for recursivity
|
||||||
@ -82,9 +80,6 @@ export default {
|
|||||||
...mapActions('explorer', [
|
...mapActions('explorer', [
|
||||||
'setDragTarget',
|
'setDragTarget',
|
||||||
]),
|
]),
|
||||||
...mapActions('notification', [
|
|
||||||
'info',
|
|
||||||
]),
|
|
||||||
select(id = this.node.item.id, doOpen = true) {
|
select(id = this.node.item.id, doOpen = true) {
|
||||||
const node = store.getters['explorer/nodeMap'][id];
|
const node = store.getters['explorer/nodeMap'][id];
|
||||||
if (!node) {
|
if (!node) {
|
||||||
@ -149,11 +144,6 @@ export default {
|
|||||||
// See https://stackoverflow.com/a/3977637/1333165
|
// See https://stackoverflow.com/a/3977637/1333165
|
||||||
evt.dataTransfer.setData('Text', '');
|
evt.dataTransfer.setData('Text', '');
|
||||||
},
|
},
|
||||||
copyPath() {
|
|
||||||
let path = utils.getAbsoluteDir(this.node).replaceAll(' ', '%20');
|
|
||||||
path = path.indexOf('/') === 0 ? path : `/${path}`;
|
|
||||||
return this.node.isFolder ? path : `${path}.md`;
|
|
||||||
},
|
|
||||||
onDrop() {
|
onDrop() {
|
||||||
const sourceNode = store.getters['explorer/dragSourceNode'];
|
const sourceNode = store.getters['explorer/dragSourceNode'];
|
||||||
const targetNode = store.getters['explorer/dragTargetNodeFolder'];
|
const targetNode = store.getters['explorer/dragTargetNodeFolder'];
|
||||||
@ -179,26 +169,22 @@ export default {
|
|||||||
top: evt.clientY,
|
top: evt.clientY,
|
||||||
},
|
},
|
||||||
items: [{
|
items: [{
|
||||||
name: '新建文件',
|
name: 'New file',
|
||||||
disabled: !this.node.isFolder || this.node.isTrash,
|
disabled: !this.node.isFolder || this.node.isTrash,
|
||||||
perform: () => explorerSvc.newItem(false),
|
perform: () => explorerSvc.newItem(false),
|
||||||
}, {
|
}, {
|
||||||
name: '新建文件夹',
|
name: 'New folder',
|
||||||
disabled: !this.node.isFolder || this.node.isTrash || this.node.isTemp,
|
disabled: !this.node.isFolder || this.node.isTrash || this.node.isTemp,
|
||||||
perform: () => explorerSvc.newItem(true),
|
perform: () => explorerSvc.newItem(true),
|
||||||
}, {
|
}, {
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
}, {
|
}, {
|
||||||
name: '重命名',
|
name: 'Rename',
|
||||||
disabled: this.node.isTrash || this.node.isTemp,
|
disabled: this.node.isTrash || this.node.isTemp,
|
||||||
perform: () => this.setEditingId(this.node.item.id),
|
perform: () => this.setEditingId(this.node.item.id),
|
||||||
}, {
|
}, {
|
||||||
name: '删除',
|
name: 'Delete',
|
||||||
perform: () => explorerSvc.deleteItem(),
|
perform: () => explorerSvc.deleteItem(),
|
||||||
}, {
|
|
||||||
name: '复制路径',
|
|
||||||
disabled: this.node.isTrash || this.node.isTemp,
|
|
||||||
perform: () => this.$refs.copyId.click(),
|
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
if (item) {
|
if (item) {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<navigation-bar></navigation-bar>
|
<navigation-bar></navigation-bar>
|
||||||
</div>
|
</div>
|
||||||
<div class="layout__panel flex flex--row" :style="{height: styles.innerHeight + 'px'}">
|
<div class="layout__panel flex flex--row" :style="{height: styles.innerHeight + 'px'}">
|
||||||
<div class="layout__panel layout__panel--editor" :class="editTheme" v-show="styles.showEditor" :style="{width: (styles.editorWidth + styles.editorGutterWidth) + 'px', fontSize: styles.fontSize + 'px'}">
|
<div class="layout__panel layout__panel--editor" :class="currTheme" v-show="styles.showEditor" :style="{width: (styles.editorWidth + styles.editorGutterWidth) + 'px', fontSize: styles.fontSize + 'px'}">
|
||||||
<div class="gutter" :style="{left: styles.editorGutterLeft + 'px'}">
|
<div class="gutter" :style="{left: styles.editorGutterLeft + 'px'}">
|
||||||
<div class="gutter__background" v-if="styles.editorGutterWidth" :style="{width: styles.editorGutterWidth + 'px'}"></div>
|
<div class="gutter__background" v-if="styles.editorGutterWidth" :style="{width: styles.editorGutterWidth + 'px'}"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -28,7 +28,6 @@
|
|||||||
<div class="gutter__background" v-if="styles.previewGutterWidth" :style="{width: styles.previewGutterWidth + 'px'}"></div>
|
<div class="gutter__background" v-if="styles.previewGutterWidth" :style="{width: styles.previewGutterWidth + 'px'}"></div>
|
||||||
</div>
|
</div>
|
||||||
<preview></preview>
|
<preview></preview>
|
||||||
<preview-in-page-buttons></preview-in-page-buttons>
|
|
||||||
<div class="gutter" :style="{left: styles.previewGutterLeft + 'px'}">
|
<div class="gutter" :style="{left: styles.previewGutterLeft + 'px'}">
|
||||||
<sticky-comment v-if="styles.previewGutterWidth && stickyComment === 'top'"></sticky-comment>
|
<sticky-comment v-if="styles.previewGutterWidth && stickyComment === 'top'"></sticky-comment>
|
||||||
<current-discussion v-if="styles.previewGutterWidth"></current-discussion>
|
<current-discussion v-if="styles.previewGutterWidth"></current-discussion>
|
||||||
@ -61,7 +60,6 @@ import Editor from './Editor';
|
|||||||
import Preview from './Preview';
|
import Preview from './Preview';
|
||||||
import Tour from './Tour';
|
import Tour from './Tour';
|
||||||
import EditorInPageButtons from './EditorInPageButtons';
|
import EditorInPageButtons from './EditorInPageButtons';
|
||||||
import PreviewInPageButtons from './PreviewInPageButtons';
|
|
||||||
import StickyComment from './gutters/StickyComment';
|
import StickyComment from './gutters/StickyComment';
|
||||||
import CurrentDiscussion from './gutters/CurrentDiscussion';
|
import CurrentDiscussion from './gutters/CurrentDiscussion';
|
||||||
import FindReplace from './FindReplace';
|
import FindReplace from './FindReplace';
|
||||||
@ -80,7 +78,6 @@ export default {
|
|||||||
Preview,
|
Preview,
|
||||||
Tour,
|
Tour,
|
||||||
EditorInPageButtons,
|
EditorInPageButtons,
|
||||||
PreviewInPageButtons,
|
|
||||||
StickyComment,
|
StickyComment,
|
||||||
CurrentDiscussion,
|
CurrentDiscussion,
|
||||||
FindReplace,
|
FindReplace,
|
||||||
@ -105,7 +102,7 @@ export default {
|
|||||||
...mapGetters('theme', [
|
...mapGetters('theme', [
|
||||||
'currEditTheme',
|
'currEditTheme',
|
||||||
]),
|
]),
|
||||||
editTheme() {
|
currTheme() {
|
||||||
return `edit-theme--${this.currEditTheme || 'default'}`;
|
return `edit-theme--${this.currEditTheme || 'default'}`;
|
||||||
},
|
},
|
||||||
showFindReplace() {
|
showFindReplace() {
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<div class="modal__button-bar">
|
<div class="modal__button-bar">
|
||||||
<button class="button" v-if="simpleModal.rejectText" @click="config.reject()">{{simpleModal.rejectText}}</button>
|
<button class="button" v-if="simpleModal.rejectText" @click="config.reject()">{{simpleModal.rejectText}}</button>
|
||||||
<button class="button button--resolve" v-if="simpleModal.resolveText" @click="config.resolve()">{{simpleModal.resolveText}}</button>
|
<button class="button button--resolve" v-if="simpleModal.resolveText" @click="config.resolve()">{{simpleModal.resolveText}}</button>
|
||||||
<button v-for="(item, idx) in (simpleModal.resolveArray || [])" class="button button--resolve" @click="config.resolve(item.value)">{{item.text}}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</modal-inner>
|
</modal-inner>
|
||||||
</div>
|
</div>
|
||||||
@ -42,7 +41,6 @@ import BadgeManagementModal from './modals/BadgeManagementModal';
|
|||||||
import SponsorModal from './modals/SponsorModal';
|
import SponsorModal from './modals/SponsorModal';
|
||||||
import CommitMessageModal from './modals/CommitMessageModal';
|
import CommitMessageModal from './modals/CommitMessageModal';
|
||||||
import WorkspaceImgPathModal from './modals/WorkspaceImgPathModal';
|
import WorkspaceImgPathModal from './modals/WorkspaceImgPathModal';
|
||||||
import ChatGptModal from './modals/ChatGptModal';
|
|
||||||
|
|
||||||
// Providers
|
// Providers
|
||||||
import GooglePhotoModal from './modals/providers/GooglePhotoModal';
|
import GooglePhotoModal from './modals/providers/GooglePhotoModal';
|
||||||
@ -66,8 +64,6 @@ import GiteeOpenModal from './modals/providers/GiteeOpenModal';
|
|||||||
import GiteeSaveModal from './modals/providers/GiteeSaveModal';
|
import GiteeSaveModal from './modals/providers/GiteeSaveModal';
|
||||||
import GiteeWorkspaceModal from './modals/providers/GiteeWorkspaceModal';
|
import GiteeWorkspaceModal from './modals/providers/GiteeWorkspaceModal';
|
||||||
import GiteePublishModal from './modals/providers/GiteePublishModal';
|
import GiteePublishModal from './modals/providers/GiteePublishModal';
|
||||||
import GiteeGistSyncModal from './modals/providers/GiteeGistSyncModal';
|
|
||||||
import GiteeGistPublishModal from './modals/providers/GiteeGistPublishModal';
|
|
||||||
import GitlabAccountModal from './modals/providers/GitlabAccountModal';
|
import GitlabAccountModal from './modals/providers/GitlabAccountModal';
|
||||||
import GitlabOpenModal from './modals/providers/GitlabOpenModal';
|
import GitlabOpenModal from './modals/providers/GitlabOpenModal';
|
||||||
import GitlabPublishModal from './modals/providers/GitlabPublishModal';
|
import GitlabPublishModal from './modals/providers/GitlabPublishModal';
|
||||||
@ -113,7 +109,6 @@ export default {
|
|||||||
SponsorModal,
|
SponsorModal,
|
||||||
CommitMessageModal,
|
CommitMessageModal,
|
||||||
WorkspaceImgPathModal,
|
WorkspaceImgPathModal,
|
||||||
ChatGptModal,
|
|
||||||
// Providers
|
// Providers
|
||||||
GooglePhotoModal,
|
GooglePhotoModal,
|
||||||
GoogleDriveAccountModal,
|
GoogleDriveAccountModal,
|
||||||
@ -136,8 +131,6 @@ export default {
|
|||||||
GiteeSaveModal,
|
GiteeSaveModal,
|
||||||
GiteeWorkspaceModal,
|
GiteeWorkspaceModal,
|
||||||
GiteePublishModal,
|
GiteePublishModal,
|
||||||
GiteeGistSyncModal,
|
|
||||||
GiteeGistPublishModal,
|
|
||||||
GitlabAccountModal,
|
GitlabAccountModal,
|
||||||
GitlabOpenModal,
|
GitlabOpenModal,
|
||||||
GitlabPublishModal,
|
GitlabPublishModal,
|
||||||
@ -188,7 +181,6 @@ export default {
|
|||||||
// User has to sign in
|
// User has to sign in
|
||||||
await store.dispatch('modal/open', 'signInForSponsorship');
|
await store.dispatch('modal/open', 'signInForSponsorship');
|
||||||
await giteeHelper.signin();
|
await giteeHelper.signin();
|
||||||
await syncSvc.afterSignIn();
|
|
||||||
syncSvc.requestSync();
|
syncSvc.requestSync();
|
||||||
}
|
}
|
||||||
if (!store.getters.isSponsor) {
|
if (!store.getters.isSponsor) {
|
||||||
|
@ -114,8 +114,7 @@ export default {
|
|||||||
publishLocations: 'current',
|
publishLocations: 'current',
|
||||||
}),
|
}),
|
||||||
pagedownButtons() {
|
pagedownButtons() {
|
||||||
const buttonShowObj = store.getters['data/computedSettings'].editor.headButtons;
|
return pagedownButtons.map(button => ({
|
||||||
return pagedownButtons.filter(it => buttonShowObj[it.method]).map(button => ({
|
|
||||||
...button,
|
...button,
|
||||||
titleWithShortcut: `${button.title}${getShortcut(button.method)}`,
|
titleWithShortcut: `${button.title}${getShortcut(button.method)}`,
|
||||||
iconClass: `icon-${button.icon}`,
|
iconClass: `icon-${button.icon}`,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="preview">
|
<div class="preview">
|
||||||
<div class="preview__inner-1" @click="onClick" @scroll="onScroll">
|
<div class="preview__inner-1" @click="onClick" @scroll="onScroll">
|
||||||
<div class="preview__inner-2" :class="previewTheme" :style="{padding: styles.previewPadding}">
|
<div class="preview__inner-2" :style="{padding: styles.previewPadding}">
|
||||||
</div>
|
</div>
|
||||||
<div class="gutter" :style="{left: styles.previewGutterLeft + 'px'}">
|
<div class="gutter" :style="{left: styles.previewGutterLeft + 'px'}">
|
||||||
<comment-list v-if="styles.previewGutterWidth"></comment-list>
|
<comment-list v-if="styles.previewGutterWidth"></comment-list>
|
||||||
@ -37,15 +37,9 @@ export default {
|
|||||||
...mapGetters('file', [
|
...mapGetters('file', [
|
||||||
'isCurrentTemp',
|
'isCurrentTemp',
|
||||||
]),
|
]),
|
||||||
...mapGetters('theme', [
|
|
||||||
'currPreviewTheme',
|
|
||||||
]),
|
|
||||||
...mapGetters('layout', [
|
...mapGetters('layout', [
|
||||||
'styles',
|
'styles',
|
||||||
]),
|
]),
|
||||||
previewTheme() {
|
|
||||||
return `preview-theme--${this.currPreviewTheme || 'default'}`;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions('data', [
|
...mapActions('data', [
|
||||||
|
@ -1,212 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="preview-in-page-buttons">
|
|
||||||
<ul>
|
|
||||||
<li class="before">
|
|
||||||
<icon-ellipsis></icon-ellipsis>
|
|
||||||
</li>
|
|
||||||
<li title="分享">
|
|
||||||
<a href="javascript:void(0)" @click="share"><icon-share></icon-share></a>
|
|
||||||
</li>
|
|
||||||
<li title="切换预览主题">
|
|
||||||
<dropdown-menu :selected="selectedTheme" :options="allThemes" :closeOnItemClick="false" @change="changeTheme">
|
|
||||||
<icon-select-theme></icon-select-theme>
|
|
||||||
</dropdown-menu>
|
|
||||||
</li>
|
|
||||||
<li title="Markdown语法帮助">
|
|
||||||
<a href="javascript:void(0)" @click="showHelp"><icon-help-circle></icon-help-circle></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapGetters, mapActions } from 'vuex';
|
|
||||||
// import juice from 'juice';
|
|
||||||
import store from '../store';
|
|
||||||
import DropdownMenu from './common/DropdownMenu';
|
|
||||||
import publishSvc from '../services/publishSvc';
|
|
||||||
import giteeGistProvider from '../services/providers/giteeGistProvider';
|
|
||||||
import gistProvider from '../services/providers/gistProvider';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
DropdownMenu,
|
|
||||||
},
|
|
||||||
data: () => ({
|
|
||||||
allThemes: [{
|
|
||||||
name: '默认主题',
|
|
||||||
value: 'default',
|
|
||||||
}, {
|
|
||||||
name: '凝夜紫',
|
|
||||||
value: 'ningyezi',
|
|
||||||
}, {
|
|
||||||
name: '草原绿',
|
|
||||||
value: 'caoyuangreen',
|
|
||||||
}, {
|
|
||||||
name: '雁栖湖',
|
|
||||||
value: 'yanqihu',
|
|
||||||
}, {
|
|
||||||
name: '灵动蓝',
|
|
||||||
value: 'activeblue',
|
|
||||||
}, {
|
|
||||||
name: '极客黑',
|
|
||||||
value: 'jikebrack',
|
|
||||||
}, {
|
|
||||||
name: '极简黑',
|
|
||||||
value: 'simplebrack',
|
|
||||||
}, {
|
|
||||||
name: '全栈蓝',
|
|
||||||
value: 'allblue',
|
|
||||||
}, {
|
|
||||||
name: '自定义',
|
|
||||||
value: 'custom',
|
|
||||||
}],
|
|
||||||
baseCss: '',
|
|
||||||
sharing: false,
|
|
||||||
}),
|
|
||||||
computed: {
|
|
||||||
...mapGetters('theme', [
|
|
||||||
'currPreviewTheme',
|
|
||||||
'customPreviewThemeStyle',
|
|
||||||
]),
|
|
||||||
...mapGetters('publishLocation', {
|
|
||||||
publishLocations: 'current',
|
|
||||||
}),
|
|
||||||
selectedTheme() {
|
|
||||||
return {
|
|
||||||
value: this.currPreviewTheme || 'default',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions('data', [
|
|
||||||
'toggleSideBar',
|
|
||||||
]),
|
|
||||||
async changeTheme(item) {
|
|
||||||
await store.dispatch('theme/setPreviewTheme', item.value);
|
|
||||||
// 如果自定义主题没内容 则弹出编辑区域
|
|
||||||
if (item.value === 'custom' && !this.customPreviewThemeStyle) {
|
|
||||||
this.toggleSideBar(true);
|
|
||||||
store.dispatch('data/setSideBarPanel', 'previewTheme');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showHelp() {
|
|
||||||
this.toggleSideBar(true);
|
|
||||||
store.dispatch('data/setSideBarPanel', 'help');
|
|
||||||
},
|
|
||||||
async share() {
|
|
||||||
if (this.sharing) {
|
|
||||||
store.dispatch('notification/info', '分享链接创建中...请稍后再试');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const currentFile = store.getters['file/current'];
|
|
||||||
await store.dispatch('modal/open', { type: 'shareHtmlPre', name: currentFile.name });
|
|
||||||
this.sharing = true;
|
|
||||||
const mainToken = store.getters['workspace/mainWorkspaceToken'];
|
|
||||||
if (!mainToken) {
|
|
||||||
store.dispatch('notification/info', '登录主文档空间之后才可使用分享功能!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let tempGistId = null;
|
|
||||||
const isGithub = mainToken.providerId === 'githubAppData';
|
|
||||||
const gistProviderId = isGithub ? 'gist' : 'giteegist';
|
|
||||||
const filterLocations = this.publishLocations.filter(it => it.providerId === gistProviderId
|
|
||||||
&& it.url && it.gistId);
|
|
||||||
if (filterLocations.length > 0) {
|
|
||||||
tempGistId = filterLocations[0].gistId;
|
|
||||||
}
|
|
||||||
const location = (isGithub ? gistProvider : giteeGistProvider).makeLocation(
|
|
||||||
mainToken,
|
|
||||||
`分享-${currentFile.name}`,
|
|
||||||
true,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
location.templateId = 'styledHtmlWithTheme';
|
|
||||||
location.fileId = currentFile.id;
|
|
||||||
location.gistId = tempGistId;
|
|
||||||
const { gistId } = await publishSvc.publishLocationAndStore(location);
|
|
||||||
const sharePage = mainToken.providerId === 'githubAppData' ? 'gistshare.html' : 'share.html';
|
|
||||||
const url = `${window.location.protocol}//${window.location.host}/${sharePage}?id=${gistId}`;
|
|
||||||
await store.dispatch('modal/open', { type: 'shareHtml', name: currentFile.name, url });
|
|
||||||
} catch (err) {
|
|
||||||
if (err) {
|
|
||||||
store.dispatch('notification/error', err);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
this.sharing = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import '../styles/variables.scss';
|
|
||||||
|
|
||||||
.preview-in-page-buttons {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 10px;
|
|
||||||
right: -98px;
|
|
||||||
height: 34px;
|
|
||||||
padding: 5px;
|
|
||||||
background-color: rgba(84, 96, 114, 0.4);
|
|
||||||
border-radius: $border-radius-base;
|
|
||||||
transition: 0.5s;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.dropdown-menu {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:focus,
|
|
||||||
&:hover {
|
|
||||||
right: 0;
|
|
||||||
transition: 0.5s;
|
|
||||||
background-color: #546072;
|
|
||||||
|
|
||||||
.dropdown-menu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-menu-items {
|
|
||||||
bottom: 100%;
|
|
||||||
top: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding: 0;
|
|
||||||
margin-left: 10px;
|
|
||||||
line-height: 20px;
|
|
||||||
|
|
||||||
li {
|
|
||||||
line-height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
list-style: none;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 14px;
|
|
||||||
margin-right: 10px;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
color: #fff;
|
|
||||||
opacity: 0.7;
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:focus,
|
|
||||||
&:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.before {
|
|
||||||
margin-left: -16px;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -24,7 +24,6 @@
|
|||||||
<pre class="markdown-highlighting" v-html="markdownSample"></pre>
|
<pre class="markdown-highlighting" v-html="markdownSample"></pre>
|
||||||
</div>
|
</div>
|
||||||
<edit-theme-menu v-else-if="panel === 'editTheme'"></edit-theme-menu>
|
<edit-theme-menu v-else-if="panel === 'editTheme'"></edit-theme-menu>
|
||||||
<preview-theme-menu v-else-if="panel === 'previewTheme'"></preview-theme-menu>
|
|
||||||
<div class="side-bar__panel side-bar__panel--toc" :class="{'side-bar__panel--hidden': panel !== 'toc'}">
|
<div class="side-bar__panel side-bar__panel--toc" :class="{'side-bar__panel--hidden': panel !== 'toc'}">
|
||||||
<toc>
|
<toc>
|
||||||
</toc>
|
</toc>
|
||||||
@ -44,7 +43,6 @@ import HistoryMenu from './menus/HistoryMenu';
|
|||||||
import ImportExportMenu from './menus/ImportExportMenu';
|
import ImportExportMenu from './menus/ImportExportMenu';
|
||||||
import WorkspaceBackupMenu from './menus/WorkspaceBackupMenu';
|
import WorkspaceBackupMenu from './menus/WorkspaceBackupMenu';
|
||||||
import EditThemeMenu from './menus/EditThemeMenu';
|
import EditThemeMenu from './menus/EditThemeMenu';
|
||||||
import PreviewThemeMenu from './menus/PreviewThemeMenu';
|
|
||||||
import markdownSample from '../data/markdownSample.md';
|
import markdownSample from '../data/markdownSample.md';
|
||||||
import markdownConversionSvc from '../services/markdownConversionSvc';
|
import markdownConversionSvc from '../services/markdownConversionSvc';
|
||||||
import store from '../store';
|
import store from '../store';
|
||||||
@ -60,7 +58,6 @@ const panelNames = {
|
|||||||
importExport: '导入/导出',
|
importExport: '导入/导出',
|
||||||
workspaceBackups: '文档空间备份',
|
workspaceBackups: '文档空间备份',
|
||||||
editTheme: '编辑区主题',
|
editTheme: '编辑区主题',
|
||||||
previewTheme: '预览区主题',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -74,7 +71,6 @@ export default {
|
|||||||
ImportExportMenu,
|
ImportExportMenu,
|
||||||
WorkspaceBackupMenu,
|
WorkspaceBackupMenu,
|
||||||
EditThemeMenu,
|
EditThemeMenu,
|
||||||
PreviewThemeMenu,
|
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
markdownSample: markdownConversionSvc.highlight(markdownSample),
|
markdownSample: markdownConversionSvc.highlight(markdownSample),
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<span class="dropdown-menu">
|
<span class="dropdown-menu">
|
||||||
<span ref="slotInfo" @click="toggleMenu()" class="dropdown-toggle">
|
<span @click="toggleMenu()" class="dropdown-toggle">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</span>
|
</span>
|
||||||
<ul class="dropdown-menu-items" :style="dropdownStyle" v-if="showMenu">
|
|
||||||
|
<ul class="dropdown-menu-items" v-if="showMenu">
|
||||||
<li v-for="(option, idx) in options" :key="idx">
|
<li v-for="(option, idx) in options" :key="idx">
|
||||||
<a href="javascript:void(0)" :class="{selected: option.value === selectedOption.value}" @click="updateOption(option)">
|
<a href="javascript:void(0)" :class="{selected: option.value === selectedOption.value}" @click="updateOption(option)">
|
||||||
{{ option.name }}
|
{{ option.name }}
|
||||||
@ -14,8 +15,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import store from '../../store';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data: () => ({
|
data: () => ({
|
||||||
selectedOption: {
|
selectedOption: {
|
||||||
@ -47,19 +46,13 @@
|
|||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
document.removeEventListener('click', this.clickHandler);
|
document.removeEventListener('click', this.clickHandler);
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
dropdownStyle() {
|
|
||||||
const height = store.state.layout.bodyHeight;
|
|
||||||
return `max-height: ${height * 0.7}px;`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
updateOption(option) {
|
updateOption(option) {
|
||||||
this.selectedOption = option;
|
this.selectedOption = option;
|
||||||
if (this.closeOnItemClick) {
|
if (this.closeOnItemClick) {
|
||||||
this.showMenu = false;
|
this.showMenu = false;
|
||||||
}
|
}
|
||||||
this.$emit('change', option);
|
this.$emit('change', this.selectedOption);
|
||||||
},
|
},
|
||||||
toggleMenu() {
|
toggleMenu() {
|
||||||
this.showMenu = !this.showMenu;
|
this.showMenu = !this.showMenu;
|
||||||
@ -91,7 +84,7 @@
|
|||||||
max-height: 450px;
|
max-height: 450px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
margin: 0;
|
margin: 2px 0 0;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
background-color: #666;
|
background-color: #666;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
<p v-if="!historyContext">同步 <b>{{currentFileName}}</b> 以启用修订历史 或者 <a href="javascript:void(0)" @click="signin">登录 Gitee</a> 或 <a href="javascript:void(0)" @click="signinWithGithub">登录 GitHub</a> 以同步您的主文档空间。</p>
|
<p v-if="!historyContext">同步 <b>{{currentFileName}}</b> 以启用修订历史 或者 <a href="javascript:void(0)" @click="signin">登录 Gitee</a> 以同步您的主文档空间。</p>
|
||||||
<p v-else-if="loading">历史版本加载中…</p>
|
<p v-else-if="loading">历史版本加载中…</p>
|
||||||
<p v-else-if="!revisionsWithSpacer.length"><b>{{currentFileName}}</b> 没有历史版本.</p>
|
<p v-else-if="!revisionsWithSpacer.length"><b>{{currentFileName}}</b> 没有历史版本.</p>
|
||||||
<div class="menu-entry menu-entry--info flex flex--row flex--align-center" v-else>
|
<div class="menu-entry menu-entry--info flex flex--row flex--align-center" v-else>
|
||||||
@ -55,7 +55,6 @@ import EditorClassApplier from '../common/EditorClassApplier';
|
|||||||
import PreviewClassApplier from '../common/PreviewClassApplier';
|
import PreviewClassApplier from '../common/PreviewClassApplier';
|
||||||
import utils from '../../services/utils';
|
import utils from '../../services/utils';
|
||||||
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
||||||
import githubHelper from '../../services/providers/helpers/githubHelper';
|
|
||||||
import syncSvc from '../../services/syncSvc';
|
import syncSvc from '../../services/syncSvc';
|
||||||
import store from '../../store';
|
import store from '../../store';
|
||||||
import badgeSvc from '../../services/badgeSvc';
|
import badgeSvc from '../../services/badgeSvc';
|
||||||
@ -169,16 +168,6 @@ export default {
|
|||||||
async signin() {
|
async signin() {
|
||||||
try {
|
try {
|
||||||
await giteeHelper.signin();
|
await giteeHelper.signin();
|
||||||
await syncSvc.afterSignIn();
|
|
||||||
syncSvc.requestSync();
|
|
||||||
} catch (e) {
|
|
||||||
// Cancel
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async signinWithGithub() {
|
|
||||||
try {
|
|
||||||
await githubHelper.signin();
|
|
||||||
await syncSvc.afterSignIn();
|
|
||||||
syncSvc.requestSync();
|
syncSvc.requestSync();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Cancel
|
// Cancel
|
||||||
|
@ -14,9 +14,6 @@
|
|||||||
<span v-if="currentWorkspace.providerId === 'giteeAppData'">
|
<span v-if="currentWorkspace.providerId === 'giteeAppData'">
|
||||||
<b>{{currentWorkspace.name}}</b> 与您的 Gitee 默认文档空间仓库同步。
|
<b>{{currentWorkspace.name}}</b> 与您的 Gitee 默认文档空间仓库同步。
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="currentWorkspace.providerId === 'githubAppData'">
|
|
||||||
<b>{{currentWorkspace.name}}</b> 与您的 GitHub 默认文档空间仓库同步。
|
|
||||||
</span>
|
|
||||||
<span v-else-if="currentWorkspace.providerId === 'googleDriveWorkspace'">
|
<span v-else-if="currentWorkspace.providerId === 'googleDriveWorkspace'">
|
||||||
<b>{{currentWorkspace.name}}</b> 与 <a :href="workspaceLocationUrl" target="_blank">Google Drive 文件夹</a>同步。
|
<b>{{currentWorkspace.name}}</b> 与 <a :href="workspaceLocationUrl" target="_blank">Google Drive 文件夹</a>同步。
|
||||||
</span>
|
</span>
|
||||||
@ -48,11 +45,6 @@
|
|||||||
<div>使用 Gitee 登录</div>
|
<div>使用 Gitee 登录</div>
|
||||||
<span>同步您的主文档空间并解锁功能。</span>
|
<span>同步您的主文档空间并解锁功能。</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
<menu-entry v-if="!loginToken" @click.native="signinWithGithub">
|
|
||||||
<icon-login slot="icon"></icon-login>
|
|
||||||
<div>使用 GitHub 登录</div>
|
|
||||||
<span>同步您的主文档空间并解锁功能。</span>
|
|
||||||
</menu-entry>
|
|
||||||
<menu-entry @click.native="setPanel('workspaces')">
|
<menu-entry @click.native="setPanel('workspaces')">
|
||||||
<icon-database slot="icon"></icon-database>
|
<icon-database slot="icon"></icon-database>
|
||||||
<div><div class="menu-entry__label menu-entry__label--count" v-if="workspaceCount">{{workspaceCount}}</div> 文档空间</div>
|
<div><div class="menu-entry__label menu-entry__label--count" v-if="workspaceCount">{{workspaceCount}}</div> 文档空间</div>
|
||||||
@ -118,11 +110,6 @@
|
|||||||
编辑区主题
|
编辑区主题
|
||||||
<span>编辑区主题样式(自定义主题可编辑)。</span>
|
<span>编辑区主题样式(自定义主题可编辑)。</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
<menu-entry @click.native="setPanel('previewTheme')">
|
|
||||||
<icon-select-theme slot="icon"></icon-select-theme>
|
|
||||||
预览区主题
|
|
||||||
<span>预览区主题样式(自定义主题可编辑)。</span>
|
|
||||||
</menu-entry>
|
|
||||||
<menu-entry @click.native="settings">
|
<menu-entry @click.native="settings">
|
||||||
<icon-settings slot="icon"></icon-settings>
|
<icon-settings slot="icon"></icon-settings>
|
||||||
<div>配置</div>
|
<div>配置</div>
|
||||||
@ -150,7 +137,6 @@ import MenuEntry from './common/MenuEntry';
|
|||||||
import providerRegistry from '../../services/providers/common/providerRegistry';
|
import providerRegistry from '../../services/providers/common/providerRegistry';
|
||||||
import UserImage from '../UserImage';
|
import UserImage from '../UserImage';
|
||||||
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
||||||
import githubHelper from '../../services/providers/helpers/githubHelper';
|
|
||||||
import syncSvc from '../../services/syncSvc';
|
import syncSvc from '../../services/syncSvc';
|
||||||
import userSvc from '../../services/userSvc';
|
import userSvc from '../../services/userSvc';
|
||||||
import store from '../../store';
|
import store from '../../store';
|
||||||
@ -203,16 +189,6 @@ export default {
|
|||||||
async signin() {
|
async signin() {
|
||||||
try {
|
try {
|
||||||
await giteeHelper.signin();
|
await giteeHelper.signin();
|
||||||
await syncSvc.afterSignIn();
|
|
||||||
syncSvc.requestSync();
|
|
||||||
} catch (e) {
|
|
||||||
// Cancel
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async signinWithGithub() {
|
|
||||||
try {
|
|
||||||
await githubHelper.signin();
|
|
||||||
await syncSvc.afterSignIn();
|
|
||||||
syncSvc.requestSync();
|
syncSvc.requestSync();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Cancel
|
// Cancel
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="preview-theme side-bar__panel side-bar__panel--menu">
|
|
||||||
<div class="side-bar__info">
|
|
||||||
<div class="menu-entry menu-entry--info flex flex--row flex--align-center">
|
|
||||||
<span v-if="currPreviewTheme==='custom'">
|
|
||||||
下面的自定义主题样式可编辑,可参考其他主题样式填入自己喜欢的预览样式。<br>
|
|
||||||
主题class为:preview-theme--custom
|
|
||||||
</span>
|
|
||||||
<span v-else>
|
|
||||||
下面的主题样式不可编辑。
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="side-bar__content">
|
|
||||||
<template v-if="currPreviewTheme === 'default'">
|
|
||||||
默认主题无额外样式,请选择其他主题。
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<code-editor v-for="(value, index) in styleEles" :key="index"
|
|
||||||
v-if="value.id === `preview-theme-${currPreviewTheme}`" lang="css" :value="value.innerHTML"
|
|
||||||
:disabled="value.id!=='preview-theme-custom'" @changed="changeText" scrollClass="side-bar__inner"></code-editor>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex--row flex--end" v-if="currPreviewTheme==='custom'">
|
|
||||||
<button class="preview-theme__button button" @click="saveStyleText">保存</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapGetters } from 'vuex';
|
|
||||||
import MenuEntry from './common/MenuEntry';
|
|
||||||
import CodeEditor from '../CodeEditor';
|
|
||||||
import store from '../../store';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
MenuEntry,
|
|
||||||
CodeEditor,
|
|
||||||
},
|
|
||||||
data: () => ({
|
|
||||||
themeStyleText: '',
|
|
||||||
styleEles: [],
|
|
||||||
}),
|
|
||||||
computed: {
|
|
||||||
...mapGetters('theme', [
|
|
||||||
'currPreviewTheme',
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
saveStyleText() {
|
|
||||||
const typeEle = this.findByTheme(this.currPreviewTheme);
|
|
||||||
if (!typeEle || !this.themeStyleText) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
typeEle.innerHTML = this.themeStyleText;
|
|
||||||
store.dispatch('theme/setCustomPreviewThemeStyle', this.themeStyleText);
|
|
||||||
store.dispatch('notification/info', '保存自定义主题样式成功!');
|
|
||||||
},
|
|
||||||
findByTheme(theme) {
|
|
||||||
const findEles = this.styleEles.filter(it => it.id === `preview-theme-${theme}`);
|
|
||||||
return findEles.length ? findEles[0] : null;
|
|
||||||
},
|
|
||||||
changeText(text) {
|
|
||||||
this.themeStyleText = text;
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
store.dispatch('data/setSideBarPanel', 'menu');
|
|
||||||
},
|
|
||||||
initStyle(theme) {
|
|
||||||
if (theme === 'default') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const value = theme || this.currPreviewTheme;
|
|
||||||
if (this.findByTheme(value)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const styleId = `preview-theme-${value}`;
|
|
||||||
const styleEle = document.getElementById(styleId);
|
|
||||||
if (!styleEle) {
|
|
||||||
setTimeout(() => this.initStyle(value), 1000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.styleEles.push(styleEle);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
currPreviewTheme: {
|
|
||||||
immediate: true,
|
|
||||||
handler(val) {
|
|
||||||
this.initStyle(val);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.initStyle();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.side-bar__panel--menu {
|
|
||||||
.side-bar__content {
|
|
||||||
.code-editor {
|
|
||||||
min-height: 400px !important;
|
|
||||||
max-height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-theme__button {
|
|
||||||
font-size: 14px;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -43,7 +43,7 @@
|
|||||||
<div v-for="token in githubTokens" :key="token.sub">
|
<div v-for="token in githubTokens" :key="token.sub">
|
||||||
<menu-entry @click.native="publishGist(token)">
|
<menu-entry @click.native="publishGist(token)">
|
||||||
<icon-provider slot="icon" provider-id="gist"></icon-provider>
|
<icon-provider slot="icon" provider-id="gist"></icon-provider>
|
||||||
<div>发布到 GitHubGist</div>
|
<div>发布到 Gist</div>
|
||||||
<span>{{token.name}}</span>
|
<span>{{token.name}}</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
<menu-entry @click.native="publishGithub(token)">
|
<menu-entry @click.native="publishGithub(token)">
|
||||||
@ -53,11 +53,6 @@
|
|||||||
</menu-entry>
|
</menu-entry>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="token in giteeTokens" :key="token.sub">
|
<div v-for="token in giteeTokens" :key="token.sub">
|
||||||
<menu-entry @click.native="publishGiteeGist(token)">
|
|
||||||
<icon-provider slot="icon" provider-id="giteegist"></icon-provider>
|
|
||||||
<div>发布到 GiteeGist</div>
|
|
||||||
<span>{{token.name}}</span>
|
|
||||||
</menu-entry>
|
|
||||||
<menu-entry @click.native="publishGitee(token)">
|
<menu-entry @click.native="publishGitee(token)">
|
||||||
<icon-provider slot="icon" provider-id="gitee"></icon-provider>
|
<icon-provider slot="icon" provider-id="gitee"></icon-provider>
|
||||||
<div>发布到 Gitee</div>
|
<div>发布到 Gitee</div>
|
||||||
@ -263,8 +258,8 @@ export default {
|
|||||||
},
|
},
|
||||||
async addGitlabAccount() {
|
async addGitlabAccount() {
|
||||||
try {
|
try {
|
||||||
const { serverUrl, applicationId, applicationSecret } = await store.dispatch('modal/open', { type: 'gitlabAccount' });
|
const { serverUrl, applicationId } = await store.dispatch('modal/open', { type: 'gitlabAccount' });
|
||||||
await gitlabHelper.addAccount(serverUrl, applicationId, applicationSecret);
|
await gitlabHelper.addAccount(serverUrl, applicationId);
|
||||||
} catch (e) { /* cancel */ }
|
} catch (e) { /* cancel */ }
|
||||||
},
|
},
|
||||||
async addGiteaAccount() {
|
async addGiteaAccount() {
|
||||||
@ -294,9 +289,8 @@ export default {
|
|||||||
publishBloggerPage: publishModalOpener('bloggerPagePublish', 'publishToBloggerPage'),
|
publishBloggerPage: publishModalOpener('bloggerPagePublish', 'publishToBloggerPage'),
|
||||||
publishDropbox: publishModalOpener('dropboxPublish', 'publishToDropbox'),
|
publishDropbox: publishModalOpener('dropboxPublish', 'publishToDropbox'),
|
||||||
publishGithub: publishModalOpener('githubPublish', 'publishToGithub'),
|
publishGithub: publishModalOpener('githubPublish', 'publishToGithub'),
|
||||||
publishGist: publishModalOpener('gistPublish', 'publishToGist'),
|
|
||||||
publishGitee: publishModalOpener('giteePublish', 'publishToGitee'),
|
publishGitee: publishModalOpener('giteePublish', 'publishToGitee'),
|
||||||
publishGiteeGist: publishModalOpener('giteeGistPublish', 'publishGiteeGist'),
|
publishGist: publishModalOpener('gistPublish', 'publishToGist'),
|
||||||
publishGitlab: publishModalOpener('gitlabPublish', 'publishToGitlab'),
|
publishGitlab: publishModalOpener('gitlabPublish', 'publishToGitlab'),
|
||||||
publishGitea: publishModalOpener('giteaPublish', 'publishToGitea'),
|
publishGitea: publishModalOpener('giteaPublish', 'publishToGitea'),
|
||||||
publishGoogleDrive: publishModalOpener('googleDrivePublish', 'publishToGoogleDrive'),
|
publishGoogleDrive: publishModalOpener('googleDrivePublish', 'publishToGoogleDrive'),
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
</menu-entry>
|
</menu-entry>
|
||||||
<menu-entry @click.native="saveGist(token)">
|
<menu-entry @click.native="saveGist(token)">
|
||||||
<icon-provider slot="icon" provider-id="gist"></icon-provider>
|
<icon-provider slot="icon" provider-id="gist"></icon-provider>
|
||||||
<div>在GitHubGist上保存</div>
|
<div>在Gist上保存</div>
|
||||||
<span>{{token.name}}</span>
|
<span>{{token.name}}</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
</div>
|
</div>
|
||||||
@ -61,11 +61,6 @@
|
|||||||
<div>在Gitee上保存</div>
|
<div>在Gitee上保存</div>
|
||||||
<span>{{token.name}}</span>
|
<span>{{token.name}}</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
<menu-entry @click.native="saveGiteeGist(token)">
|
|
||||||
<icon-provider slot="icon" provider-id="giteegist"></icon-provider>
|
|
||||||
<div>在GiteeGist上保存</div>
|
|
||||||
<span>{{token.name}}</span>
|
|
||||||
</menu-entry>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-for="token in gitlabTokens" :key="token.sub">
|
<div v-for="token in gitlabTokens" :key="token.sub">
|
||||||
<menu-entry @click.native="openGitlab(token)">
|
<menu-entry @click.native="openGitlab(token)">
|
||||||
@ -239,8 +234,8 @@ export default {
|
|||||||
},
|
},
|
||||||
async addGitlabAccount() {
|
async addGitlabAccount() {
|
||||||
try {
|
try {
|
||||||
const { serverUrl, applicationId, applicationSecret } = await store.dispatch('modal/open', { type: 'gitlabAccount' });
|
const { serverUrl, applicationId } = await store.dispatch('modal/open', { type: 'gitlabAccount' });
|
||||||
await gitlabHelper.addAccount(serverUrl, applicationId, applicationSecret);
|
await gitlabHelper.addAccount(serverUrl, applicationId);
|
||||||
} catch (e) { /* cancel */ }
|
} catch (e) { /* cancel */ }
|
||||||
},
|
},
|
||||||
async addGiteaAccount() {
|
async addGiteaAccount() {
|
||||||
@ -335,12 +330,6 @@ export default {
|
|||||||
badgeSvc.addBadge('saveOnGist');
|
badgeSvc.addBadge('saveOnGist');
|
||||||
} catch (e) { /* cancel */ }
|
} catch (e) { /* cancel */ }
|
||||||
},
|
},
|
||||||
async saveGiteeGist(token) {
|
|
||||||
try {
|
|
||||||
await openSyncModal(token, 'giteeGistSync');
|
|
||||||
badgeSvc.addBadge('saveOnGiteeGist');
|
|
||||||
} catch (e) { /* cancel */ }
|
|
||||||
},
|
|
||||||
async openGitlab(token) {
|
async openGitlab(token) {
|
||||||
try {
|
try {
|
||||||
const syncLocation = await store.dispatch('modal/open', {
|
const syncLocation = await store.dispatch('modal/open', {
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<div class="workspace" v-for="(workspace, id) in workspacesById" :key="id">
|
<div class="workspace" v-for="(workspace, id) in workspacesById" :key="id">
|
||||||
<menu-entry :href="workspace.url" target="_blank">
|
<menu-entry :href="workspace.url" target="_blank">
|
||||||
<icon-provider v-if="id === 'main' && !workspace.sub" slot="icon" :provider-id="'stackedit'"></icon-provider>
|
<icon-provider slot="icon" :provider-id="workspace.providerId"></icon-provider>
|
||||||
<icon-provider v-else slot="icon" :provider-id="workspace.providerId"></icon-provider>
|
|
||||||
<div class="workspace__name"><div class="menu-entry__label" v-if="currentWorkspace === workspace">当前</div>{{workspace.name}}</div>
|
<div class="workspace__name"><div class="menu-entry__label" v-if="currentWorkspace === workspace">当前</div>{{workspace.name}}</div>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
</div>
|
</div>
|
||||||
@ -86,8 +85,8 @@ export default {
|
|||||||
},
|
},
|
||||||
async addGitlabWorkspace() {
|
async addGitlabWorkspace() {
|
||||||
try {
|
try {
|
||||||
const { serverUrl, applicationId, applicationSecret } = await store.dispatch('modal/open', { type: 'gitlabAccount' });
|
const { serverUrl, applicationId } = await store.dispatch('modal/open', { type: 'gitlabAccount' });
|
||||||
const token = await gitlabHelper.addAccount(serverUrl, applicationId, applicationSecret);
|
const token = await gitlabHelper.addAccount(serverUrl, applicationId);
|
||||||
store.dispatch('modal/open', {
|
store.dispatch('modal/open', {
|
||||||
type: 'gitlabWorkspace',
|
type: 'gitlabWorkspace',
|
||||||
token,
|
token,
|
||||||
|
@ -248,8 +248,8 @@ export default {
|
|||||||
},
|
},
|
||||||
async addGitlabAccount() {
|
async addGitlabAccount() {
|
||||||
try {
|
try {
|
||||||
const { serverUrl, applicationId, applicationSecret } = await store.dispatch('modal/open', { type: 'gitlabAccount' });
|
const { serverUrl, applicationId } = await store.dispatch('modal/open', { type: 'gitlabAccount' });
|
||||||
await gitlabHelper.addAccount(serverUrl, applicationId, applicationSecret);
|
await gitlabHelper.addAccount(serverUrl, applicationId);
|
||||||
} catch (e) { /* cancel */ }
|
} catch (e) { /* cancel */ }
|
||||||
},
|
},
|
||||||
async addGiteaAccount() {
|
async addGiteaAccount() {
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
<template>
|
|
||||||
<modal-inner class="modal__inner-1--chatgpt" aria-label="chatgpt">
|
|
||||||
<div class="modal__content">
|
|
||||||
<div class="modal__image">
|
|
||||||
<icon-chat-gpt></icon-chat-gpt>
|
|
||||||
</div>
|
|
||||||
<p><b>ChatGPT内容生成</b><br>生成时长受ChatGPT服务响应与网络响应时长影响,时间可能较长</p>
|
|
||||||
<form-entry label="生成内容要求详细描述" error="content">
|
|
||||||
<textarea slot="field" class="text-input" type="text" placeholder="输入内容(支持换行)" v-model.trim="content" :disabled="generating"></textarea>
|
|
||||||
<div class="form-entry__info">
|
|
||||||
使用 <a href="https://api35.pxj123.cn/" target="_blank">api35.pxj123.cn</a> 的免费接口生成内容,AI模型是:GPT-3.5 Turbo。
|
|
||||||
</div>
|
|
||||||
</form-entry>
|
|
||||||
<div class="modal__result">
|
|
||||||
<pre class="result_pre" v-if="generating && !result">(等待生成中...)</pre>
|
|
||||||
<pre class="result_pre" v-else v-text="result"></pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal__button-bar">
|
|
||||||
<button class="button" @click="reject()">{{ generating ? '停止' : '关闭' }}</button>
|
|
||||||
<button class="button button--resolve" @click="generate" v-if="!generating && !!content">{{ !!result ? '重新生成' : '开始生成' }}</button>
|
|
||||||
<button class="button button--resolve" @click="resolve" v-if="!generating && !!result">确认插入</button>
|
|
||||||
</div>
|
|
||||||
</modal-inner>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import modalTemplate from './common/modalTemplate';
|
|
||||||
import chatGptSvc from '../../services/chatGptSvc';
|
|
||||||
import store from '../../store';
|
|
||||||
|
|
||||||
export default modalTemplate({
|
|
||||||
data: () => ({
|
|
||||||
generating: false,
|
|
||||||
content: '',
|
|
||||||
result: '',
|
|
||||||
xhr: null,
|
|
||||||
}),
|
|
||||||
methods: {
|
|
||||||
resolve(evt) {
|
|
||||||
evt.preventDefault();
|
|
||||||
const { callback } = this.config;
|
|
||||||
this.config.resolve();
|
|
||||||
callback(this.result);
|
|
||||||
},
|
|
||||||
process({ done, content, error }) {
|
|
||||||
if (done) {
|
|
||||||
this.generating = false;
|
|
||||||
// 已结束
|
|
||||||
} else if (content) {
|
|
||||||
this.result = this.result + content;
|
|
||||||
const container = document.querySelector('.result_pre');
|
|
||||||
container.scrollTo(0, container.scrollHeight); // 滚动到最底部
|
|
||||||
} else if (error) {
|
|
||||||
this.generating = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
generate() {
|
|
||||||
this.generating = true;
|
|
||||||
this.result = '';
|
|
||||||
try {
|
|
||||||
this.xhr = chatGptSvc.chat({
|
|
||||||
content: `${this.content}\n(使用Markdown方式输出结果)`,
|
|
||||||
}, this.process);
|
|
||||||
} catch (err) {
|
|
||||||
this.generating = false;
|
|
||||||
store.dispatch('notification/error', err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
reject() {
|
|
||||||
if (this.generating) {
|
|
||||||
if (this.xhr) {
|
|
||||||
this.xhr.abort();
|
|
||||||
this.generating = false;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { callback } = this.config;
|
|
||||||
this.config.reject();
|
|
||||||
callback(null);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
const script = document.createElement('script');
|
|
||||||
script.src = `https://api35.pxj123.cn/js/chat.js?t=${new Date().getTime()}`;
|
|
||||||
script.onload = () => {
|
|
||||||
/* eslint-disable */
|
|
||||||
console.log('加载外部chatgpt的js成功!');
|
|
||||||
};
|
|
||||||
this.$el.appendChild(script);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import '../../styles/variables.scss';
|
|
||||||
|
|
||||||
.modal__inner-1.modal__inner-1--chatgpt {
|
|
||||||
max-width: 560px;
|
|
||||||
|
|
||||||
.result_pre {
|
|
||||||
font-size: 0.9em;
|
|
||||||
font-variant-ligatures: no-common-ligatures;
|
|
||||||
line-height: 1.25;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-break: break-word;
|
|
||||||
word-wrap: break-word;
|
|
||||||
height: 300px;
|
|
||||||
border: 1px solid rgb(126, 126, 126);
|
|
||||||
border-radius: $border-radius-base;
|
|
||||||
padding: 10px;
|
|
||||||
overflow-y: scroll; /* 开启垂直滚动条 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.result_pre::-webkit-scrollbar {
|
|
||||||
display: none; /* 隐藏滚动条 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.result_pre.scroll-bottom {
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
}
|
|
||||||
|
|
||||||
.config-warning {
|
|
||||||
color: #f00;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-input {
|
|
||||||
min-height: 60px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -2,12 +2,9 @@
|
|||||||
<modal-inner aria-label="提交信息">
|
<modal-inner aria-label="提交信息">
|
||||||
<p>自定义 <b>{{ config.name }}</b> 提交信息。</p>
|
<p>自定义 <b>{{ config.name }}</b> 提交信息。</p>
|
||||||
<div class="modal__content">
|
<div class="modal__content">
|
||||||
<div class="form-entry">
|
<form-entry label="提交信息">
|
||||||
<label class="form-entry__label">提交信息</label>
|
<input slot="field" class="textfield" placeholder="提交信息非必填" type="text" v-model.trim="commitMessage" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__field">
|
</form-entry>
|
||||||
<input slot="field" class="textfield" placeholder="提交信息非必填" type="text" v-model.trim="commitMessage" @keydown.enter="resolve()">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__button-bar">
|
<div class="modal__button-bar">
|
||||||
<button class="button" @click="config.reject()">取消</button>
|
<button class="button" @click="config.reject()">取消</button>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<modal-inner aria-label="导出到PDF">
|
<modal-inner aria-label="导出到PDF">
|
||||||
<div class="modal__content">
|
<div class="modal__content">
|
||||||
<p>请为您的<b> pdf导出</b>选择模板。(该导出很消耗服务器资源,文档太大或图片太多可能会导出超时失败!可参考 <a href="https://gitee.com/mafgwo/stackedit/blob/master/docs/大文档导出PDF方式.md" target="_blank">大文档导出PDF方式</a> 自行导出大文档!)</p>
|
<p>请为您的<b> pdf导出</b>选择模板。</p>
|
||||||
<form-entry label="模板">
|
<form-entry label="模板">
|
||||||
<select class="textfield" slot="field" v-model="selectedTemplate" @keydown.enter="resolve()">
|
<select class="textfield" slot="field" v-model="selectedTemplate" @keydown.enter="resolve()">
|
||||||
<option v-for="(template, id) in allTemplatesById" :key="id" :value="id">
|
<option v-for="(template, id) in allTemplatesById" :key="id" :value="id">
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
<div class="modal__image">
|
<div class="modal__image">
|
||||||
<icon-upload></icon-upload>
|
<icon-upload></icon-upload>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="publishLocations.length"><b>{{currentFileName}}</b> 被发布到了以下位置:</p>
|
<p v-if="publishLocations.length"><b>{{currentFileName}}</b> is published to the following location(s):</p>
|
||||||
<p v-else><b>{{currentFileName}}</b> 还没有被发布.</p>
|
<p v-else><b>{{currentFileName}}</b> is not published yet.</p>
|
||||||
<div>
|
<div>
|
||||||
<div class="publish-entry flex flex--column" v-for="location in publishLocations" :key="location.id">
|
<div class="publish-entry flex flex--column" v-for="location in publishLocations" :key="location.id">
|
||||||
<div class="publish-entry__header flex flex--row flex--align-center">
|
<div class="publish-entry__header flex flex--row flex--align-center">
|
||||||
@ -26,7 +26,7 @@
|
|||||||
{{location.url}}
|
{{location.url}}
|
||||||
</div>
|
</div>
|
||||||
<div class="publish-entry__buttons flex flex--row flex--center" v-if="location.url">
|
<div class="publish-entry__buttons flex flex--row flex--center" v-if="location.url">
|
||||||
<button class="publish-entry__button button" v-clipboard="location.url" @click="info('位置URL已复制到剪贴板!')" v-title="'复制URL'">
|
<button class="publish-entry__button button" v-clipboard="location.url" @click="info('Location URL copied to clipboard!')" v-title="'复制URL'">
|
||||||
<icon-content-copy></icon-content-copy>
|
<icon-content-copy></icon-content-copy>
|
||||||
</button>
|
</button>
|
||||||
<a class="publish-entry__button button" v-if="location.url" :href="location.url" target="_blank" v-title="'打开位置'">
|
<a class="publish-entry__button button" v-if="location.url" :href="location.url" target="_blank" v-title="'打开位置'">
|
||||||
@ -34,19 +34,6 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="publish-entry__row flex flex--row flex--align-center" v-if="shareUrl(location)">
|
|
||||||
<div class="publish-entry__url">
|
|
||||||
分享链接: {{shareUrl(location)}}
|
|
||||||
</div>
|
|
||||||
<div class="publish-entry__buttons flex flex--row flex--center">
|
|
||||||
<button class="publish-entry__button button" v-clipboard="shareUrl(location)" @click="info('分享URL已复制到剪贴板!')" v-title="'复制分享URL'">
|
|
||||||
<icon-content-copy></icon-content-copy>
|
|
||||||
</button>
|
|
||||||
<a class="publish-entry__button button" :href="shareUrl(location)" target="_blank" v-title="'打开分享'">
|
|
||||||
<icon-open-in-new></icon-open-in-new>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__info" v-if="publishLocations.length">
|
<div class="modal__info" v-if="publishLocations.length">
|
||||||
@ -88,16 +75,6 @@ export default {
|
|||||||
store.commit('publishLocation/deleteItem', location.id);
|
store.commit('publishLocation/deleteItem', location.id);
|
||||||
badgeSvc.addBadge('removePublishLocation');
|
badgeSvc.addBadge('removePublishLocation');
|
||||||
},
|
},
|
||||||
shareUrl(location) {
|
|
||||||
if (location.providerId !== 'giteegist' && location.providerId !== 'gist') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!location.url || !location.gistId) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const sharePage = location.providerId === 'gist' ? 'gistshare.html' : 'share.html';
|
|
||||||
return `${window.location.protocol}//${window.location.host}/${sharePage}?id=${location.gistId}`;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
<div class="flex flex--column">
|
<div class="flex flex--column">
|
||||||
<div class="workspace-entry__header flex flex--row flex--align-center">
|
<div class="workspace-entry__header flex flex--row flex--align-center">
|
||||||
<div class="workspace-entry__icon">
|
<div class="workspace-entry__icon">
|
||||||
<icon-provider v-if="id === 'main' && !workspace.sub" :provider-id="'stackedit'"></icon-provider>
|
<icon-provider :provider-id="workspace.providerId"></icon-provider>
|
||||||
<icon-provider v-else :provider-id="workspace.providerId"></icon-provider>
|
|
||||||
</div>
|
</div>
|
||||||
<input class="text-input" type="text" v-if="editedId === id" v-focus @blur="submitEdit()" @keydown.enter="submitEdit()" @keydown.esc.stop="submitEdit(true)" v-model="editingName">
|
<input class="text-input" type="text" v-if="editedId === id" v-focus @blur="submitEdit()" @keydown.enter="submitEdit()" @keydown.esc.stop="submitEdit(true)" v-model="editingName">
|
||||||
<div class="workspace-entry__name" v-else>{{workspace.name}}</div>
|
<div class="workspace-entry__name" v-else>{{workspace.name}}</div>
|
||||||
@ -18,7 +17,7 @@
|
|||||||
<button class="workspace-entry__button button" @click="edit(id)" v-title="'编辑名称'">
|
<button class="workspace-entry__button button" @click="edit(id)" v-title="'编辑名称'">
|
||||||
<icon-pen></icon-pen>
|
<icon-pen></icon-pen>
|
||||||
</button>
|
</button>
|
||||||
<template v-if="workspace.providerId === 'giteeAppData' || workspace.providerId === 'githubAppData' || workspace.providerId === 'githubWorkspace'
|
<template v-if="workspace.providerId === 'giteeAppData' || workspace.providerId === 'githubWorkspace'
|
||||||
|| workspace.providerId === 'giteeWorkspace' || workspace.providerId === 'gitlabWorkspace' || workspace.providerId === 'giteaWorkspace'">
|
|| workspace.providerId === 'giteeWorkspace' || workspace.providerId === 'gitlabWorkspace' || workspace.providerId === 'giteaWorkspace'">
|
||||||
<button class="workspace-entry__button button" @click="stopAutoSync(id)" v-if="workspace.autoSync == undefined || workspace.autoSync" v-title="'关闭自动同步'">
|
<button class="workspace-entry__button button" @click="stopAutoSync(id)" v-if="workspace.autoSync == undefined || workspace.autoSync" v-title="'关闭自动同步'">
|
||||||
<icon-sync-auto></icon-sync-auto>
|
<icon-sync-auto></icon-sync-auto>
|
||||||
|
@ -17,7 +17,7 @@ export default {
|
|||||||
uid: utils.uid(),
|
uid: utils.uid(),
|
||||||
}),
|
}),
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$el.querySelector('input,select,textarea').id = this.uid;
|
this.$el.querySelector('input,select').id = this.uid;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<modal-inner aria-label="发布到GitHubGist">
|
<modal-inner aria-label="发布到Gist">
|
||||||
<div class="modal__content">
|
<div class="modal__content">
|
||||||
<div class="modal__image">
|
<div class="modal__image">
|
||||||
<icon-provider provider-id="gist"></icon-provider>
|
<icon-provider provider-id="gist"></icon-provider>
|
||||||
</div>
|
</div>
|
||||||
<p>发布<b> {{CurrentFileName}} </b>到<b>GitHubGist</b>。</p>
|
<p>发布<b> {{CurrentFileName}} </b>到<b>Gist</b>。</p>
|
||||||
<form-entry label="文件名" error="filename">
|
<form-entry label="Filename" error="filename">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="filename" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="filename" @keydown.enter="resolve()">
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<div class="form-entry">
|
<div class="form-entry">
|
||||||
@ -15,10 +15,10 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form-entry label="存在Gist ID" info="可选的">
|
<form-entry label="Existing Gist ID" info="可选的">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
如果文件存在于GitHubGist中,则将被覆盖。
|
如果文件存在于Gist中,则将被覆盖。
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="Template">
|
<form-entry label="Template">
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<modal-inner aria-label="与 GitHubGist 同步">
|
<modal-inner aria-label="与 Gist 同步">
|
||||||
<div class="modal__content">
|
<div class="modal__content">
|
||||||
<div class="modal__image">
|
<div class="modal__image">
|
||||||
<icon-provider provider-id="gist"></icon-provider>
|
<icon-provider provider-id="gist"></icon-provider>
|
||||||
</div>
|
</div>
|
||||||
<p>将<b> {{currentFileName}} </b>保存到<b>GitHubGist</b>并保持同步。</p>
|
<p>将<b> {{currentFileName}} </b>保存到<b>Gist</b>并保持同步。</p>
|
||||||
<form-entry label="文件名" error="filename">
|
<form-entry label="Filename" error="filename">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="filename" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="filename" @keydown.enter="resolve()">
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<div class="form-entry">
|
<div class="form-entry">
|
||||||
@ -15,10 +15,10 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form-entry label="存在Gist ID" info="可选的">
|
<form-entry label="Existing Gist ID" info="可选的">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
如果文件存在于GitHubGist中,则将被覆盖。
|
如果文件存在于Gist中,则将被覆盖。
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,7 +41,6 @@
|
|||||||
import modalTemplate from '../common/modalTemplate';
|
import modalTemplate from '../common/modalTemplate';
|
||||||
import constants from '../../../data/constants';
|
import constants from '../../../data/constants';
|
||||||
import store from '../../../store';
|
import store from '../../../store';
|
||||||
import networkSvc from '../../../services/networkSvc';
|
|
||||||
|
|
||||||
export default modalTemplate({
|
export default modalTemplate({
|
||||||
data: () => ({
|
data: () => ({
|
||||||
@ -66,9 +65,6 @@ export default modalTemplate({
|
|||||||
return !!confClientId && !!confServerUrl;
|
return !!confClientId && !!confServerUrl;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
networkSvc.getServerConf();
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
resolve() {
|
resolve() {
|
||||||
if (this.useServerConf) {
|
if (this.useServerConf) {
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
<div class="modal__image">
|
<div class="modal__image">
|
||||||
<icon-provider provider-id="gitea"></icon-provider>
|
<icon-provider provider-id="gitea"></icon-provider>
|
||||||
</div>
|
</div>
|
||||||
<p>向您的<b> Gitea </b>项目发布<b> {{ currentFileName }} </b>。</p>
|
<p>向您的<b> Gitea </b>项目发布<b> {{CurrentFileName}} </b>。</p>
|
||||||
<form-entry label="Project URL" error="projectUrl">
|
<form-entry label="Project URL" error="projectUrl">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
<b>例如:</b> {{ config.token.serverUrl }}/path/to/project
|
<b>例如:</b> {{config.token.serverUrl}}/path/to/project
|
||||||
</div>
|
</div>
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<form-entry label="File path" error="path">
|
<form-entry label="File path" error="path">
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
<template>
|
|
||||||
<modal-inner aria-label="发布到GiteeGist">
|
|
||||||
<div class="modal__content">
|
|
||||||
<div class="modal__image">
|
|
||||||
<icon-provider provider-id="giteegist"></icon-provider>
|
|
||||||
</div>
|
|
||||||
<p>发布<b> {{CurrentFileName}} </b>到<b>GiteeGist</b>。</p>
|
|
||||||
<form-entry label="文件名" error="filename">
|
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="filename" @keydown.enter="resolve()">
|
|
||||||
</form-entry>
|
|
||||||
<div class="form-entry">
|
|
||||||
<div class="form-entry__checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" v-model="isPublic"> 公开的
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<form-entry label="存在Gist ID" info="可选的">
|
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
|
||||||
<div class="form-entry__info">
|
|
||||||
如果文件存在于GiteeGist中,则将被覆盖。
|
|
||||||
</div>
|
|
||||||
</form-entry>
|
|
||||||
<form-entry label="Template">
|
|
||||||
<select slot="field" class="textfield" v-model="selectedTemplate" @keydown.enter="resolve()">
|
|
||||||
<option v-for="(template, id) in allTemplatesById" :key="id" :value="id">
|
|
||||||
{{ template.name }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<div class="form-entry__actions">
|
|
||||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
|
||||||
</div>
|
|
||||||
</form-entry>
|
|
||||||
<div class="modal__info">
|
|
||||||
<b>ProTip:</b> You can provide a value for <code>title</code> in the <a href="javascript:void(0)" @click="openFileProperties">file properties</a>.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal__button-bar">
|
|
||||||
<button class="button" @click="config.reject()">取消</button>
|
|
||||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
|
||||||
</div>
|
|
||||||
</modal-inner>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import giteeGistProvider from '../../../services/providers/giteeGistProvider';
|
|
||||||
import modalTemplate from '../common/modalTemplate';
|
|
||||||
|
|
||||||
export default modalTemplate({
|
|
||||||
data: () => ({
|
|
||||||
filename: '',
|
|
||||||
gistId: '',
|
|
||||||
}),
|
|
||||||
computedLocalSettings: {
|
|
||||||
isPublic: 'gistIsPublic',
|
|
||||||
selectedTemplate: 'gistPublishTemplate',
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.filename = `${this.currentFileName}.md`;
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
resolve() {
|
|
||||||
if (!this.filename) {
|
|
||||||
this.setError('filename');
|
|
||||||
} else {
|
|
||||||
// Return new location
|
|
||||||
const location = giteeGistProvider.makeLocation(
|
|
||||||
this.config.token,
|
|
||||||
this.filename,
|
|
||||||
this.isPublic,
|
|
||||||
this.gistId,
|
|
||||||
);
|
|
||||||
location.templateId = this.selectedTemplate;
|
|
||||||
this.config.resolve(location);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -1,64 +0,0 @@
|
|||||||
<template>
|
|
||||||
<modal-inner aria-label="与 GiteeGist 同步">
|
|
||||||
<div class="modal__content">
|
|
||||||
<div class="modal__image">
|
|
||||||
<icon-provider provider-id="giteegist"></icon-provider>
|
|
||||||
</div>
|
|
||||||
<p>将<b> {{currentFileName}} </b>保存到<b>GiteeGist</b>并保持同步。</p>
|
|
||||||
<form-entry label="文件名" error="filename">
|
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="filename" @keydown.enter="resolve()">
|
|
||||||
</form-entry>
|
|
||||||
<div class="form-entry">
|
|
||||||
<div class="form-entry__checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" v-model="isPublic"> 公开的
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<form-entry label="存在Gist ID" info="可选的">
|
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
|
||||||
<div class="form-entry__info">
|
|
||||||
如果文件存在于GiteeGist中,则将被覆盖。
|
|
||||||
</div>
|
|
||||||
</form-entry>
|
|
||||||
</div>
|
|
||||||
<div class="modal__button-bar">
|
|
||||||
<button class="button" @click="config.reject()">取消</button>
|
|
||||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
|
||||||
</div>
|
|
||||||
</modal-inner>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import giteeGistProvider from '../../../services/providers/giteeGistProvider';
|
|
||||||
import modalTemplate from '../common/modalTemplate';
|
|
||||||
|
|
||||||
export default modalTemplate({
|
|
||||||
data: () => ({
|
|
||||||
filename: '',
|
|
||||||
gistId: '',
|
|
||||||
}),
|
|
||||||
computedLocalSettings: {
|
|
||||||
isPublic: 'gistIsPublic',
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.filename = `${this.currentFileName}.md`;
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
resolve() {
|
|
||||||
if (!this.filename) {
|
|
||||||
this.setError('filename');
|
|
||||||
} else {
|
|
||||||
// Return new location
|
|
||||||
const location = giteeGistProvider.makeLocation(
|
|
||||||
this.config.token,
|
|
||||||
this.filename,
|
|
||||||
this.isPublic,
|
|
||||||
this.gistId,
|
|
||||||
);
|
|
||||||
this.config.resolve(location);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -4,7 +4,7 @@
|
|||||||
<div class="modal__image">
|
<div class="modal__image">
|
||||||
<icon-provider provider-id="gitee"></icon-provider>
|
<icon-provider provider-id="gitee"></icon-provider>
|
||||||
</div>
|
</div>
|
||||||
<p>保存 <b>{{currentFileName}}</b> 并与您的 <b>Gitee</b> 仓库保持同步.</p>
|
<p>Save <b>{{currentFileName}}</b> to your <b>Gitee</b> repository and keep it synced.</p>
|
||||||
<form-entry label="仓库URL" error="repoUrl">
|
<form-entry label="仓库URL" error="repoUrl">
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="repoUrl" @keydown.enter="resolve()">
|
<input slot="field" class="textfield" type="text" v-model.trim="repoUrl" @keydown.enter="resolve()">
|
||||||
<div class="form-entry__info">
|
<div class="form-entry__info">
|
||||||
|
@ -5,30 +5,22 @@
|
|||||||
<icon-provider provider-id="gitlab"></icon-provider>
|
<icon-provider provider-id="gitlab"></icon-provider>
|
||||||
</div>
|
</div>
|
||||||
<p>将您的<b>GitLab</b>链接到<b>StackEdit中文版</b>。</p>
|
<p>将您的<b>GitLab</b>链接到<b>StackEdit中文版</b>。</p>
|
||||||
<template v-if="!useServerConf">
|
<form-entry label="GitLab URL" error="serverUrl">
|
||||||
<form-entry label="GitLab URL" error="serverUrl">
|
<input v-if="config.forceServerUrl" slot="field" class="textfield" type="text" disabled="disabled" v-model="config.forceServerUrl">
|
||||||
<input v-if="config.forceServerUrl" slot="field" class="textfield" type="text" disabled="disabled" v-model="config.forceServerUrl">
|
<input v-else slot="field" class="textfield" type="text" v-model.trim="serverUrl" @keydown.enter="resolve()">
|
||||||
<input v-else slot="field" class="textfield" type="text" v-model.trim="serverUrl" @keydown.enter="resolve()">
|
<div class="form-entry__info">
|
||||||
<div class="form-entry__info">
|
<b>例如:</b> https://gitlab.example.com/
|
||||||
<b>例如:</b> https://gitlab.example.com/
|
</div>
|
||||||
<span v-if="httpAppUrl">
|
</form-entry>
|
||||||
,非https的URL,请跳转到 <a :href="httpAppUrl" target="_blank">HTTP链接</a> 添加Gitlab。
|
<form-entry label="Application ID" error="applicationId">
|
||||||
</span>
|
<input slot="field" class="textfield" type="text" v-model.trim="applicationId" @keydown.enter="resolve()">
|
||||||
</div>
|
<div class="form-entry__info">
|
||||||
</form-entry>
|
您必须使用重定向url <b>{{redirectUrl}}</b>配置OAuth2应用程序
|
||||||
<form-entry label="Application ID" error="applicationId">
|
</div>
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="applicationId" @keydown.enter="resolve()">
|
<div class="form-entry__actions">
|
||||||
</form-entry>
|
<a href="https://docs.gitlab.com/ee/integration/oauth_provider.html" target="_blank">更多信息</a>
|
||||||
<form-entry label="Application Secret" error="applicationSecret">
|
</div>
|
||||||
<input slot="field" class="textfield" type="text" v-model.trim="applicationSecret" @keydown.enter="resolve()">
|
</form-entry>
|
||||||
<div class="form-entry__info">
|
|
||||||
您必须使用重定向url <b>{{redirectUrl}}</b>配置OAuth2应用程序
|
|
||||||
</div>
|
|
||||||
<div class="form-entry__actions">
|
|
||||||
<a href="https://docs.gitlab.com/ee/integration/oauth_provider.html" target="_blank">更多信息</a>
|
|
||||||
</div>
|
|
||||||
</form-entry>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__button-bar">
|
<div class="modal__button-bar">
|
||||||
<button class="button" @click="config.reject()">取消</button>
|
<button class="button" @click="config.reject()">取消</button>
|
||||||
@ -40,8 +32,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import modalTemplate from '../common/modalTemplate';
|
import modalTemplate from '../common/modalTemplate';
|
||||||
import constants from '../../../data/constants';
|
import constants from '../../../data/constants';
|
||||||
import store from '../../../store';
|
|
||||||
import networkSvc from '../../../services/networkSvc';
|
|
||||||
|
|
||||||
export default modalTemplate({
|
export default modalTemplate({
|
||||||
data: () => ({
|
data: () => ({
|
||||||
@ -50,31 +40,9 @@ export default modalTemplate({
|
|||||||
computedLocalSettings: {
|
computedLocalSettings: {
|
||||||
serverUrl: 'gitlabServerUrl',
|
serverUrl: 'gitlabServerUrl',
|
||||||
applicationId: 'gitlabApplicationId',
|
applicationId: 'gitlabApplicationId',
|
||||||
applicationSecret: 'gitlabApplicationSecret',
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
httpAppUrl() {
|
|
||||||
if (constants.origin.indexOf('https://') === 0 && this.serverUrl.indexOf('http://') === 0) {
|
|
||||||
return `${constants.origin.replace('https://', 'http://')}/app`;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
// 是否使用服务端配置
|
|
||||||
useServerConf() {
|
|
||||||
const confClientId = store.getters['data/serverConf'].gitlabClientId;
|
|
||||||
const confServerUrl = store.getters['data/serverConf'].gitlabUrl;
|
|
||||||
return !!confClientId && !!confServerUrl;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
networkSvc.getServerConf();
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
resolve() {
|
resolve() {
|
||||||
if (this.useServerConf) {
|
|
||||||
this.config.resolve({});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const serverUrl = this.config.forceServerUrl || this.serverUrl;
|
const serverUrl = this.config.forceServerUrl || this.serverUrl;
|
||||||
if (!serverUrl) {
|
if (!serverUrl) {
|
||||||
this.setError('serverUrl');
|
this.setError('serverUrl');
|
||||||
@ -82,18 +50,14 @@ export default modalTemplate({
|
|||||||
if (!this.applicationId) {
|
if (!this.applicationId) {
|
||||||
this.setError('applicationId');
|
this.setError('applicationId');
|
||||||
}
|
}
|
||||||
if (!this.applicationSecret) {
|
if (serverUrl && this.applicationId) {
|
||||||
this.setError('applicationSecret');
|
const parsedUrl = serverUrl.match(/^(https:\/\/[^/]+)/);
|
||||||
}
|
|
||||||
if (serverUrl && this.applicationId && this.applicationSecret) {
|
|
||||||
const parsedUrl = serverUrl.match(/^(http[s]?:\/\/[^/]+)/);
|
|
||||||
if (!parsedUrl) {
|
if (!parsedUrl) {
|
||||||
this.setError('serverUrl');
|
this.setError('serverUrl');
|
||||||
} else {
|
} else {
|
||||||
this.config.resolve({
|
this.config.resolve({
|
||||||
serverUrl: parsedUrl[1],
|
serverUrl: parsedUrl[1],
|
||||||
applicationId: this.applicationId,
|
applicationId: this.applicationId,
|
||||||
applicationSecret: this.applicationSecret,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,6 @@ export default {
|
|||||||
'badgeCreations',
|
'badgeCreations',
|
||||||
'serverConf',
|
'serverConf',
|
||||||
],
|
],
|
||||||
textMaxLength: 10000000,
|
textMaxLength: 250000,
|
||||||
defaultName: 'Untitled',
|
defaultName: 'Untitled',
|
||||||
};
|
};
|
||||||
|
@ -24,7 +24,6 @@ export default () => ({
|
|||||||
giteePublishTemplate: 'jekyllSite',
|
giteePublishTemplate: 'jekyllSite',
|
||||||
gitlabServerUrl: '',
|
gitlabServerUrl: '',
|
||||||
gitlabApplicationId: '',
|
gitlabApplicationId: '',
|
||||||
gitlabApplicationSecret: '',
|
|
||||||
gitlabProjectUrl: '',
|
gitlabProjectUrl: '',
|
||||||
gitlabWorkspaceProjectUrl: '',
|
gitlabWorkspaceProjectUrl: '',
|
||||||
gitlabPublishTemplate: 'plainText',
|
gitlabPublishTemplate: 'plainText',
|
||||||
|
@ -17,34 +17,6 @@ editor:
|
|||||||
monospacedFontOnly: false
|
monospacedFontOnly: false
|
||||||
# 是否显示右上角图标
|
# 是否显示右上角图标
|
||||||
showInPageButtons: true
|
showInPageButtons: true
|
||||||
# 头部的按钮是否显示独立设置
|
|
||||||
headButtons:
|
|
||||||
# 加粗
|
|
||||||
bold: true
|
|
||||||
# 斜体
|
|
||||||
italic: true
|
|
||||||
# 标题
|
|
||||||
heading: true
|
|
||||||
# 删除线
|
|
||||||
strikethrough: true
|
|
||||||
# 无序列表
|
|
||||||
ulist: true
|
|
||||||
# 有序列表
|
|
||||||
olist: true
|
|
||||||
# 可选列表
|
|
||||||
clist: true
|
|
||||||
# 块引用
|
|
||||||
quote: true
|
|
||||||
# 代码
|
|
||||||
code: true
|
|
||||||
# 表格
|
|
||||||
table: true
|
|
||||||
# 链接
|
|
||||||
link: true
|
|
||||||
# 图片
|
|
||||||
image: true
|
|
||||||
# ChatGPT
|
|
||||||
chatgpt: true
|
|
||||||
|
|
||||||
# Keyboard shortcuts
|
# Keyboard shortcuts
|
||||||
# See https://craig.is/killing/mice
|
# See https://craig.is/killing/mice
|
||||||
@ -59,7 +31,6 @@ shortcuts:
|
|||||||
mod+shift+h: heading
|
mod+shift+h: heading
|
||||||
mod+shift+r: hr
|
mod+shift+r: hr
|
||||||
mod+shift+g: image
|
mod+shift+g: image
|
||||||
mod+shift+p: chatgpt
|
|
||||||
mod+shift+i: italic
|
mod+shift+i: italic
|
||||||
mod+shift+l: link
|
mod+shift+l: link
|
||||||
mod+shift+o: olist
|
mod+shift+o: olist
|
||||||
@ -68,8 +39,6 @@ shortcuts:
|
|||||||
mod+shift+t: table
|
mod+shift+t: table
|
||||||
mod+shift+u: ulist
|
mod+shift+u: ulist
|
||||||
mod+shift+f: inlineformula
|
mod+shift+f: inlineformula
|
||||||
# 切换编辑与预览模式
|
|
||||||
mod+shift+e: toggleeditor
|
|
||||||
'= = > space':
|
'= = > space':
|
||||||
method: expand
|
method: expand
|
||||||
params:
|
params:
|
||||||
@ -113,16 +82,16 @@ turndown:
|
|||||||
|
|
||||||
# GitHub/GitLab/Gitee/Gitea commit messages
|
# GitHub/GitLab/Gitee/Gitea commit messages
|
||||||
git:
|
git:
|
||||||
createFileMessage: '{{path}} created from https://md.jonylee.top/'
|
createFileMessage: '{{path}} created from https://stackedit.cn/'
|
||||||
updateFileMessage: '{{path}} updated from https://md.jonylee.top/'
|
updateFileMessage: '{{path}} updated from https://stackedit.cn/'
|
||||||
deleteFileMessage: '{{path}} deleted from https://md.jonylee.top/'
|
deleteFileMessage: '{{path}} deleted from https://stackedit.cn/'
|
||||||
|
|
||||||
# Default content for new files
|
# Default content for new files
|
||||||
newFileContent: |
|
newFileContent: |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
> Written with [Markdown编辑器-StackEdit中文版](https://md.jonylee.top/).
|
> Written with [StackEdit中文版](https://stackedit.cn/).
|
||||||
|
|
||||||
# Default properties for new files
|
# Default properties for new files
|
||||||
newFileProperties: |
|
newFileProperties: |
|
||||||
|
@ -158,19 +158,7 @@ export default [
|
|||||||
new Feature(
|
new Feature(
|
||||||
'sponsor',
|
'sponsor',
|
||||||
'赞助',
|
'赞助',
|
||||||
'使用 Gitee 登录并赞助 StackEdit 以解锁 PDF 和 Pandoc 导出。(暂不支持赞助)',
|
'使用 Google 登录并赞助 StackEdit 以解锁 PDF 和 Pandoc 导出。(暂不支持赞助)',
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
new Feature(
|
|
||||||
'githubSignIn',
|
|
||||||
'登录',
|
|
||||||
'使用 Gitee 登录,同步您的主文档空间并解锁功能。',
|
|
||||||
[
|
|
||||||
new Feature(
|
|
||||||
'githubSyncMainWorkspace',
|
|
||||||
'主文档空间已同步',
|
|
||||||
'使用 GitHub 登录以将您的主文档空间与您的默认空间stackedit-app-data仓库数据同步。',
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -328,11 +316,6 @@ export default [
|
|||||||
'GitHub保存',
|
'GitHub保存',
|
||||||
'使用“同步”菜单将文件保存在GitHub仓库中。',
|
'使用“同步”菜单将文件保存在GitHub仓库中。',
|
||||||
),
|
),
|
||||||
new Feature(
|
|
||||||
'saveOnGist',
|
|
||||||
'GitHubGist保存',
|
|
||||||
'使用“同步”菜单将文件保存在GitHubGist中。',
|
|
||||||
),
|
|
||||||
new Feature(
|
new Feature(
|
||||||
'openFromGitee',
|
'openFromGitee',
|
||||||
'Gitee阅读器',
|
'Gitee阅读器',
|
||||||
@ -344,9 +327,9 @@ export default [
|
|||||||
'使用“同步”菜单将文件保存在Gitee仓库中。',
|
'使用“同步”菜单将文件保存在Gitee仓库中。',
|
||||||
),
|
),
|
||||||
new Feature(
|
new Feature(
|
||||||
'saveOnGiteeGist',
|
'saveOnGist',
|
||||||
'GiteeGist保存',
|
'Gist保存',
|
||||||
'使用“同步”菜单将文件保存在GiteeGist中。',
|
'使用“同步”菜单将文件保存在GIST中。',
|
||||||
),
|
),
|
||||||
new Feature(
|
new Feature(
|
||||||
'openFromGitlab',
|
'openFromGitlab',
|
||||||
@ -422,19 +405,14 @@ export default [
|
|||||||
),
|
),
|
||||||
new Feature(
|
new Feature(
|
||||||
'publishToGist',
|
'publishToGist',
|
||||||
'GitHubGist发布',
|
'Gist发布',
|
||||||
'使用“发布”菜单将文件发布到GitHubGist。',
|
'使用“发布”菜单将文件发布到GIST。',
|
||||||
),
|
),
|
||||||
new Feature(
|
new Feature(
|
||||||
'publishToGitee',
|
'publishToGitee',
|
||||||
'Gitee发布',
|
'Gitee发布',
|
||||||
'使用“发布”菜单将文件发布到Gitee仓库。',
|
'使用“发布”菜单将文件发布到Gitee仓库。',
|
||||||
),
|
),
|
||||||
new Feature(
|
|
||||||
'publishToGiteeGist',
|
|
||||||
'GiteeGist发布',
|
|
||||||
'使用“发布”菜单将文件发布到GiteeGist。',
|
|
||||||
),
|
|
||||||
new Feature(
|
new Feature(
|
||||||
'publishToGitlab',
|
'publishToGitlab',
|
||||||
'GitLab发布',
|
'GitLab发布',
|
||||||
|
@ -15,7 +15,7 @@ export default [{
|
|||||||
method: 'strikethrough',
|
method: 'strikethrough',
|
||||||
title: '删除线',
|
title: '删除线',
|
||||||
icon: 'format-strikethrough',
|
icon: 'format-strikethrough',
|
||||||
// }, {
|
}, {
|
||||||
}, {
|
}, {
|
||||||
method: 'ulist',
|
method: 'ulist',
|
||||||
title: '无序列表',
|
title: '无序列表',
|
||||||
@ -28,7 +28,7 @@ export default [{
|
|||||||
method: 'clist',
|
method: 'clist',
|
||||||
title: '可选列表',
|
title: '可选列表',
|
||||||
icon: 'format-list-checks',
|
icon: 'format-list-checks',
|
||||||
// }, {
|
}, {
|
||||||
}, {
|
}, {
|
||||||
method: 'quote',
|
method: 'quote',
|
||||||
title: '块引用',
|
title: '块引用',
|
||||||
@ -49,8 +49,4 @@ export default [{
|
|||||||
method: 'image',
|
method: 'image',
|
||||||
title: '图片',
|
title: '图片',
|
||||||
icon: 'file-image',
|
icon: 'file-image',
|
||||||
}, {
|
|
||||||
method: 'chatgpt',
|
|
||||||
title: 'ChatGPT',
|
|
||||||
icon: 'chat-gpt',
|
|
||||||
}];
|
}];
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
const simpleModal = (contentHtml, rejectText, resolveText, resolveArray) => ({
|
const simpleModal = (contentHtml, rejectText, resolveText) => ({
|
||||||
contentHtml: typeof contentHtml === 'function' ? contentHtml : () => contentHtml,
|
contentHtml: typeof contentHtml === 'function' ? contentHtml : () => contentHtml,
|
||||||
rejectText,
|
rejectText,
|
||||||
resolveArray,
|
|
||||||
resolveText,
|
resolveText,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -61,40 +60,17 @@ export default {
|
|||||||
'取消',
|
'取消',
|
||||||
'确认清理',
|
'确认清理',
|
||||||
),
|
),
|
||||||
shareHtml: simpleModal(
|
|
||||||
config => `<p>给文档 "${config.name}" 创建了分享链接如下:<br/><a href="${config.url}" target="_blank">${config.url}</a><br/>关闭该窗口后可以到发布中查看分享链接。</p>`,
|
|
||||||
'关闭窗口',
|
|
||||||
),
|
|
||||||
shareHtmlPre: simpleModal(
|
|
||||||
config => `<p>将给文档 "${config.name}" 创建分享链接,创建后将会把文档公开发布到默认空间账号的Gist中。您确定吗?</p>`,
|
|
||||||
'取消',
|
|
||||||
'确认分享',
|
|
||||||
),
|
|
||||||
signInForComment: simpleModal(
|
signInForComment: simpleModal(
|
||||||
`<p>您必须使用 Gitee或GitHub 登录默认文档空间后才能开始评论。</p>
|
`<p>您必须使用 Google 登录才能开始评论。</p>
|
||||||
<div class="modal__info"><b>注意:</b> 这将同步您的主文档空间。</div>`,
|
<div class="modal__info"><b>注意:</b> 这将同步您的主文档空间。</div>`,
|
||||||
'取消',
|
'取消',
|
||||||
'',
|
'确认登录',
|
||||||
[{
|
|
||||||
text: 'Gitee登录',
|
|
||||||
value: 'gitee',
|
|
||||||
}, {
|
|
||||||
text: 'GitHub登录',
|
|
||||||
value: 'github',
|
|
||||||
}],
|
|
||||||
),
|
),
|
||||||
signInForSponsorship: simpleModal(
|
signInForSponsorship: simpleModal(
|
||||||
`<p>您必须使用 Gitee或GitHub 登录才能赞助。</p>
|
`<p>您必须使用 Google 登录才能赞助。</p>
|
||||||
<div class="modal__info"><b>注意:</b> 这将同步您的主文档空间。</div>`,
|
<div class="modal__info"><b>注意:</b> 这将同步您的主文档空间。</div>`,
|
||||||
'取消',
|
'取消',
|
||||||
'',
|
'确认登录',
|
||||||
[{
|
|
||||||
text: 'Gitee登录',
|
|
||||||
value: 'gitee',
|
|
||||||
}, {
|
|
||||||
text: 'GitHub登录',
|
|
||||||
value: 'github',
|
|
||||||
}],
|
|
||||||
),
|
),
|
||||||
sponsorOnly: simpleModal(
|
sponsorOnly: simpleModal(
|
||||||
'<p>此功能仅限于赞助商,因为它依赖于服务器资源。</p>',
|
'<p>此功能仅限于赞助商,因为它依赖于服务器资源。</p>',
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>{{files.0.name}}</title>
|
|
||||||
<link rel="stylesheet" href="https://stackedit.cn/style.css" />
|
|
||||||
<style type="text/css">
|
|
||||||
.app--dark {
|
|
||||||
background-color: #444;
|
|
||||||
}
|
|
||||||
.app--dark .stackedit__html {
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
.app--dark .stackedit__content {
|
|
||||||
padding: 1px 20px 20px;
|
|
||||||
}
|
|
||||||
{{{files.0.content.themeStyleContent}}}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
{{#if pdf}}
|
|
||||||
<body class="stackedit stackedit--pdf">
|
|
||||||
{{else}}
|
|
||||||
<body class="stackedit {{{files.0.content.colorThemeClass}}}">
|
|
||||||
{{/if}}
|
|
||||||
<div class="stackedit__left">
|
|
||||||
<div class="stackedit__toc">
|
|
||||||
{{#tocToHtml files.0.content.toc 2}}{{/tocToHtml}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="stackedit__right">
|
|
||||||
<div class="stackedit__html">
|
|
||||||
<div class="stackedit__content {{{files.0.content.themeClass}}}">
|
|
||||||
{{{files.0.content.html}}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
@ -1,36 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>{{files.0.name}}</title>
|
|
||||||
<link rel="stylesheet" href="https://stackedit.cn/style.css" />
|
|
||||||
<style type="text/css">
|
|
||||||
.app--dark {
|
|
||||||
background-color: #444;
|
|
||||||
}
|
|
||||||
.app--dark .stackedit__html {
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
.app--dark .stackedit__content {
|
|
||||||
padding: 1px 20px 20px;
|
|
||||||
}
|
|
||||||
{{{files.0.content.themeStyleContent}}}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
{{#if pdf}}
|
|
||||||
<body class="stackedit stackedit--pdf">
|
|
||||||
{{else}}
|
|
||||||
<body class="stackedit {{{files.0.content.colorThemeClass}}}">
|
|
||||||
{{/if}}
|
|
||||||
<div class="stackedit__html">
|
|
||||||
<div class="stackedit__content {{{files.0.content.themeClass}}}">
|
|
||||||
{{{files.0.content.html}}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
@ -56,7 +56,6 @@ export default (md) => {
|
|||||||
|
|
||||||
// According to http://pandoc.org/README.html#extension-auto_identifiers
|
// According to http://pandoc.org/README.html#extension-auto_identifiers
|
||||||
let slug = headingContent
|
let slug = headingContent
|
||||||
.replace(/<img[^>]*>/g, '') // Replace image to empty
|
|
||||||
.replace(/\s/g, '-') // Replace all spaces and newlines with hyphens
|
.replace(/\s/g, '-') // Replace all spaces and newlines with hyphens
|
||||||
.replace(/[\0-,/:-@[-^`{-~]/g, '') // Remove all punctuation, except underscores, hyphens, and periods
|
.replace(/[\0-,/:-@[-^`{-~]/g, '') // Remove all punctuation, except underscores, hyphens, and periods
|
||||||
.toLowerCase(); // Convert all alphabetic characters to lowercase
|
.toLowerCase(); // Convert all alphabetic characters to lowercase
|
||||||
@ -65,9 +64,7 @@ export default (md) => {
|
|||||||
let i;
|
let i;
|
||||||
for (i = 0; i < slug.length; i += 1) {
|
for (i = 0; i < slug.length; i += 1) {
|
||||||
const charCode = slug.charCodeAt(i);
|
const charCode = slug.charCodeAt(i);
|
||||||
if ((charCode >= 0x30 && charCode <= 0x39) || // 0-9
|
if ((charCode >= 0x61 && charCode <= 0x7A) || charCode > 0x7E) {
|
||||||
(charCode >= 0x61 && charCode <= 0x7A) || // a-z
|
|
||||||
charCode > 0x7E) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,23 +23,13 @@ function texMath(state, silent) {
|
|||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
function getIndex(tempStartMathPos) {
|
const endMarkerPos = state.src.indexOf(endMarker, startMathPos);
|
||||||
const tempEndMarkerPos = state.src.indexOf(endMarker, tempStartMathPos);
|
|
||||||
if (tempEndMarkerPos === -1) {
|
|
||||||
return tempEndMarkerPos;
|
|
||||||
}
|
|
||||||
if (state.src.charCodeAt(tempEndMarkerPos - 1) === 0x5C /* \ */) {
|
|
||||||
if (state.src.length - 1 > tempEndMarkerPos) {
|
|
||||||
return getIndex(tempEndMarkerPos + 1);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return tempEndMarkerPos;
|
|
||||||
}
|
|
||||||
const endMarkerPos = getIndex(startMathPos);
|
|
||||||
if (endMarkerPos === -1) {
|
if (endMarkerPos === -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (state.src.charCodeAt(endMarkerPos - 1) === 0x5C /* \ */) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const nextPos = endMarkerPos + endMarker.length;
|
const nextPos = endMarkerPos + endMarker.length;
|
||||||
if (endMarker.length === 1) {
|
if (endMarker.length === 1) {
|
||||||
// Skip if $ is preceded by a space character
|
// Skip if $ is preceded by a space character
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
<template>
|
|
||||||
<svg class="icon" width="24px" height="24px" viewBox="140 140 520 520"><defs><linearGradient id="linear" x1="100%" y1="22%" x2="0%" y2="78%"><stop offset="0%" stop-color="rgb(131,211,231)"></stop><stop offset="2%" stop-color="rgb(127,203,229)"></stop><stop offset="25%" stop-color="rgb(86,115,217)"></stop><stop offset="49%" stop-color="rgb(105,80,190)"></stop><stop offset="98%" stop-color="rgb(197,59,119)"></stop><stop offset="100%" stop-color="rgb(197,59,119)"></stop></linearGradient></defs><path id="logo" d="m617.24 354a126.36 126.36 0 0 0 -10.86-103.79 127.8 127.8 0 0 0 -137.65-61.32 126.36 126.36 0 0 0 -95.31-42.49 127.81 127.81 0 0 0 -121.92 88.49 126.4 126.4 0 0 0 -84.5 61.3 127.82 127.82 0 0 0 15.72 149.86 126.36 126.36 0 0 0 10.86 103.79 127.81 127.81 0 0 0 137.65 61.32 126.36 126.36 0 0 0 95.31 42.49 127.81 127.81 0 0 0 121.96-88.54 126.4 126.4 0 0 0 84.5-61.3 127.82 127.82 0 0 0 -15.76-149.81zm-190.66 266.49a94.79 94.79 0 0 1 -60.85-22c.77-.42 2.12-1.16 3-1.7l101-58.34a16.42 16.42 0 0 0 8.3-14.37v-142.39l42.69 24.65a1.52 1.52 0 0 1 .83 1.17v117.92a95.18 95.18 0 0 1 -94.97 95.06zm-204.24-87.23a94.74 94.74 0 0 1 -11.34-63.7c.75.45 2.06 1.25 3 1.79l101 58.34a16.44 16.44 0 0 0 16.59 0l123.31-71.2v49.3a1.53 1.53 0 0 1 -.61 1.31l-102.1 58.95a95.16 95.16 0 0 1 -129.85-34.79zm-26.57-220.49a94.71 94.71 0 0 1 49.48-41.68c0 .87-.05 2.41-.05 3.48v116.68a16.41 16.41 0 0 0 8.29 14.36l123.31 71.19-42.69 24.65a1.53 1.53 0 0 1 -1.44.13l-102.11-59a95.16 95.16 0 0 1 -34.79-129.81zm350.74 81.62-123.31-71.2 42.69-24.64a1.53 1.53 0 0 1 1.44-.13l102.11 58.95a95.08 95.08 0 0 1 -14.69 171.55c0-.88 0-2.42 0-3.49v-116.68a16.4 16.4 0 0 0 -8.24-14.36zm42.49-63.95c-.75-.46-2.06-1.25-3-1.79l-101-58.34a16.46 16.46 0 0 0 -16.59 0l-123.31 71.2v-49.3a1.53 1.53 0 0 1 .61-1.31l102.1-58.9a95.07 95.07 0 0 1 141.19 98.44zm-267.11 87.87-42.7-24.65a1.52 1.52 0 0 1 -.83-1.17v-117.92a95.07 95.07 0 0 1 155.9-73c-.77.42-2.11 1.16-3 1.7l-101 58.34a16.41 16.41 0 0 0 -8.3 14.36zm23.19-50 54.92-31.72 54.92 31.7v63.42l-54.92 31.7-54.92-31.7z" fill="#202123"></path></svg>
|
|
||||||
</template>
|
|
@ -1,3 +0,0 @@
|
|||||||
<template>
|
|
||||||
<svg t="1669462755056" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6069" width="32" height="32"><path d="M704 202.666667a96 96 0 0 1 96 96v554.666666a96 96 0 0 1-96 96H213.333333A96 96 0 0 1 117.333333 853.333333V298.666667A96 96 0 0 1 213.333333 202.666667h490.666667z m0 64H213.333333A32 32 0 0 0 181.333333 298.666667v554.666666a32 32 0 0 0 32 32h490.666667a32 32 0 0 0 32-32V298.666667a32 32 0 0 0-32-32z" fill="#212121" p-id="6070"></path><path d="M277.333333 362.666667m32 0l298.666667 0q32 0 32 32l0 0q0 32-32 32l-298.666667 0q-32 0-32-32l0 0q0-32 32-32Z" fill="#212121" p-id="6071"></path><path d="M277.333333 512m32 0l298.666667 0q32 0 32 32l0 0q0 32-32 32l-298.666667 0q-32 0-32-32l0 0q0-32 32-32Z" fill="#212121" p-id="6072"></path><path d="M277.333333 661.333333m32 0l170.666667 0q32 0 32 32l0 0q0 32-32 32l-170.666667 0q-32 0-32-32l0 0q0-32 32-32Z" fill="#212121" p-id="6073"></path><path d="M320 138.666667h512A32 32 0 0 1 864 170.666667v576a32 32 0 0 0 64 0V170.666667A96 96 0 0 0 832 74.666667H320a32 32 0 0 0 0 64z" fill="#212121" p-id="6074"></path></svg>
|
|
||||||
</template>
|
|
@ -1,3 +0,0 @@
|
|||||||
<template>
|
|
||||||
<svg t="1669464773854" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8666" width="32" height="32"><path d="M621.714286 713.142857l0 109.714286q0 22.820571-16.018286 38.838857t-38.838857 16.018286l-109.714286 0q-22.820571 0-38.838857-16.018286t-16.018286-38.838857l0-109.714286q0-22.820571 16.018286-38.838857t38.838857-16.018286l109.714286 0q22.820571 0 38.838857 16.018286t16.018286 38.838857zM621.714286 420.571429l0 109.714286q0 22.820571-16.018286 38.838857t-38.838857 16.018286l-109.714286 0q-22.820571 0-38.838857-16.018286t-16.018286-38.838857l0-109.714286q0-22.820571 16.018286-38.838857t38.838857-16.018286l109.714286 0q22.820571 0 38.838857 16.018286t16.018286 38.838857zM621.714286 128l0 109.714286q0 22.820571-16.018286 38.838857t-38.838857 16.018286l-109.714286 0q-22.820571 0-38.838857-16.018286t-16.018286-38.838857l0-109.714286q0-22.820571 16.018286-38.838857t38.838857-16.018286l109.714286 0q22.820571 0 38.838857 16.018286t16.018286 38.838857z" p-id="8667"></path></svg>
|
|
||||||
</template>
|
|
@ -15,7 +15,6 @@ export default {
|
|||||||
return 'google-drive';
|
return 'google-drive';
|
||||||
case 'googlePhotos':
|
case 'googlePhotos':
|
||||||
return 'google-photos';
|
return 'google-photos';
|
||||||
case 'githubAppData':
|
|
||||||
case 'githubWorkspace':
|
case 'githubWorkspace':
|
||||||
return 'github';
|
return 'github';
|
||||||
case 'gist':
|
case 'gist':
|
||||||
@ -30,10 +29,7 @@ export default {
|
|||||||
return 'couchdb';
|
return 'couchdb';
|
||||||
case 'giteeAppData':
|
case 'giteeAppData':
|
||||||
case 'giteeWorkspace':
|
case 'giteeWorkspace':
|
||||||
case 'giteegist':
|
|
||||||
return 'gitee';
|
return 'gitee';
|
||||||
case 'stackedit':
|
|
||||||
return 'stackedit';
|
|
||||||
default:
|
default:
|
||||||
return this.providerId;
|
return this.providerId;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
<template>
|
|
||||||
<svg t="1680140298859" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2766" width="32" height="32"><path d="M769.14815 670.390403c-44.430932 0-84.182284 19.999496-110.768803 51.471278L389.219117 565.736878c6.597255-16.571421 10.228969-34.653241 10.228969-53.594639 0-17.006326-2.940982-33.332153-8.320503-48.497551l270.88143-157.119457c26.511817 29.069059 64.702628 47.312562 107.138112 47.312562 80.055291 0 144.95337-64.899102 144.95337-144.95337 0-80.055291-64.898079-144.954393-144.95337-144.954393s-144.95337 64.899102-144.95337 144.954393c0 15.991206 2.600221 31.386848 7.382131 45.776579L359.655801 412.377048c-26.417673-27.833929-63.756069-45.181015-105.161085-45.181015-80.055291 0-144.954393 64.890916-144.954393 144.946206 0 80.055291 64.898079 144.967696 144.954393 144.967696 39.409568 0 75.128071-15.741519 101.256148-41.24845l274.172383 159.024853c-3.725858 12.8384-5.729491 26.409486-5.729491 40.457434 0 80.0645 64.898079 144.954393 144.95337 144.954393s144.95337-64.889893 144.95337-144.954393C914.101519 735.297692 849.20344 670.390403 769.14815 670.390403z" p-id="2767"></path></svg>
|
|
||||||
</template>
|
|
@ -62,10 +62,6 @@ import SwitchTheme from './SwitchTheme';
|
|||||||
import Search from './Search';
|
import Search from './Search';
|
||||||
import FindReplace from './FindReplace';
|
import FindReplace from './FindReplace';
|
||||||
import SelectTheme from './SelectTheme';
|
import SelectTheme from './SelectTheme';
|
||||||
import Copy from './Copy';
|
|
||||||
import Ellipsis from './Ellipsis';
|
|
||||||
import Share from './Share';
|
|
||||||
import ChatGpt from './ChatGpt';
|
|
||||||
|
|
||||||
Vue.component('iconProvider', Provider);
|
Vue.component('iconProvider', Provider);
|
||||||
Vue.component('iconFormatBold', FormatBold);
|
Vue.component('iconFormatBold', FormatBold);
|
||||||
@ -130,7 +126,3 @@ Vue.component('iconSwitchTheme', SwitchTheme);
|
|||||||
Vue.component('iconSearch', Search);
|
Vue.component('iconSearch', Search);
|
||||||
Vue.component('iconFindReplace', FindReplace);
|
Vue.component('iconFindReplace', FindReplace);
|
||||||
Vue.component('iconSelectTheme', SelectTheme);
|
Vue.component('iconSelectTheme', SelectTheme);
|
||||||
Vue.component('iconCopy', Copy);
|
|
||||||
Vue.component('iconEllipsis', Ellipsis);
|
|
||||||
Vue.component('iconShare', Share);
|
|
||||||
Vue.component('iconChatGpt', ChatGpt);
|
|
||||||
|
@ -122,7 +122,6 @@ function Pagedown(options) {
|
|||||||
hooks.addNoop("onPreviewRefresh"); // called with no arguments after the preview has been refreshed
|
hooks.addNoop("onPreviewRefresh"); // called with no arguments after the preview has been refreshed
|
||||||
hooks.addNoop("postBlockquoteCreation"); // called with the user's selection *after* the blockquote was created; should return the actual to-be-inserted text
|
hooks.addNoop("postBlockquoteCreation"); // called with the user's selection *after* the blockquote was created; should return the actual to-be-inserted text
|
||||||
hooks.addFalse("insertImageDialog");
|
hooks.addFalse("insertImageDialog");
|
||||||
hooks.addFalse("insertChatGptDialog");
|
|
||||||
/* called with one parameter: a callback to be called with the URL of the image. If the application creates
|
/* called with one parameter: a callback to be called with the URL of the image. If the application creates
|
||||||
* its own image insertion dialog, this hook should return true, and the callback should be called with the chosen
|
* its own image insertion dialog, this hook should return true, and the callback should be called with the chosen
|
||||||
* image url (or null if the user cancelled). If this hook returns false, the default dialog will be used.
|
* image url (or null if the user cancelled). If this hook returns false, the default dialog will be used.
|
||||||
@ -478,7 +477,6 @@ function UIManager(input, commandManager) {
|
|||||||
buttons.image = bindCommand(function (chunk, postProcessing) {
|
buttons.image = bindCommand(function (chunk, postProcessing) {
|
||||||
return this.doLinkOrImage(chunk, postProcessing, true);
|
return this.doLinkOrImage(chunk, postProcessing, true);
|
||||||
});
|
});
|
||||||
buttons.chatgpt = bindCommand("doChatGpt");
|
|
||||||
buttons.olist = bindCommand(function (chunk, postProcessing) {
|
buttons.olist = bindCommand(function (chunk, postProcessing) {
|
||||||
this.doList(chunk, postProcessing, true);
|
this.doList(chunk, postProcessing, true);
|
||||||
});
|
});
|
||||||
@ -848,17 +846,6 @@ commandProto.doLinkOrImage = function (chunk, postProcessing, isImage) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
commandProto.doChatGpt = function (chunk, postProcessing) {
|
|
||||||
var enteredCallback = function (content) {
|
|
||||||
if (content !== null) {
|
|
||||||
chunk.before = `${chunk.before}${content}`;
|
|
||||||
chunk.selection = '';
|
|
||||||
}
|
|
||||||
postProcessing();
|
|
||||||
};
|
|
||||||
this.hooks.insertChatGptDialog(enteredCallback);
|
|
||||||
};
|
|
||||||
|
|
||||||
// When making a list, hitting shift-enter will put your cursor on the next line
|
// When making a list, hitting shift-enter will put your cursor on the next line
|
||||||
// at the current indent level.
|
// at the current indent level.
|
||||||
commandProto.doAutoindent = function (chunk) {
|
commandProto.doAutoindent = function (chunk) {
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
import store from '../store';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
chat({ content }, callback) {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
const url = 'https://api.openai-proxy.com/v1/chat/completions';
|
|
||||||
xhr.open('POST', url);
|
|
||||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
|
||||||
xhr.setRequestHeader('Authorization', `Bearer ${window.my_api_key}`);
|
|
||||||
xhr.send(JSON.stringify({
|
|
||||||
model: 'gpt-3.5-turbo',
|
|
||||||
max_tokens: 3000,
|
|
||||||
top_p: 0,
|
|
||||||
temperature: 0.9,
|
|
||||||
frequency_penalty: 0,
|
|
||||||
presence_penalty: 0,
|
|
||||||
messages: [{ role: 'user', content }],
|
|
||||||
stream: true,
|
|
||||||
}));
|
|
||||||
let lastRespLen = 0;
|
|
||||||
xhr.onprogress = () => {
|
|
||||||
const responseText = xhr.response.substr(lastRespLen);
|
|
||||||
lastRespLen = xhr.response.length;
|
|
||||||
responseText.split('\n\n')
|
|
||||||
.filter(l => l.length > 0)
|
|
||||||
.forEach((text) => {
|
|
||||||
const item = text.substr(6);
|
|
||||||
if (item === '[DONE]') {
|
|
||||||
callback({ done: true });
|
|
||||||
} else {
|
|
||||||
const data = JSON.parse(item);
|
|
||||||
callback({ content: data.choices[0].delta.content });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
xhr.onerror = () => {
|
|
||||||
store.dispatch('notification/error', 'ChatGPT接口请求异常!');
|
|
||||||
callback({ error: 'ChatGPT接口请求异常!' });
|
|
||||||
};
|
|
||||||
return xhr;
|
|
||||||
},
|
|
||||||
};
|
|
@ -217,8 +217,8 @@ const editorSvc = Object.assign(new Vue(), editorSvcDiscussions, editorSvcUtils,
|
|||||||
];
|
];
|
||||||
|
|
||||||
Array.prototype.slice.call(sectionPreviewElt.getElementsByTagName('a')).forEach((aElt) => {
|
Array.prototype.slice.call(sectionPreviewElt.getElementsByTagName('a')).forEach((aElt) => {
|
||||||
const url = aElt.attributes && aElt.attributes.href && aElt.attributes.href.nodeValue;
|
const url = aElt.attributes.href.nodeValue;
|
||||||
if (!url || url.indexOf('http://') >= 0 || url.indexOf('https://') >= 0 || url.indexOf('#') >= 0) {
|
if (url.indexOf('http://') >= 0 || url.indexOf('https://') >= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
aElt.href = 'javascript:void(0);'; // eslint-disable-line no-script-url
|
aElt.href = 'javascript:void(0);'; // eslint-disable-line no-script-url
|
||||||
@ -233,21 +233,6 @@ const editorSvc = Object.assign(new Vue(), editorSvcDiscussions, editorSvcUtils,
|
|||||||
const clonedElt = headingElt.cloneNode(true);
|
const clonedElt = headingElt.cloneNode(true);
|
||||||
clonedElt.removeAttribute('id');
|
clonedElt.removeAttribute('id');
|
||||||
sectionTocElt.appendChild(clonedElt);
|
sectionTocElt.appendChild(clonedElt);
|
||||||
// 创建一个新的 <span> 元素
|
|
||||||
const contentElt = document.createElement('span');
|
|
||||||
contentElt.className = 'content';
|
|
||||||
// 将原始内容移动到新的 <span> 元素中
|
|
||||||
while (headingElt.firstChild) {
|
|
||||||
contentElt.appendChild(headingElt.firstChild);
|
|
||||||
}
|
|
||||||
const prefixElt = document.createElement('span');
|
|
||||||
prefixElt.className = 'prefix';
|
|
||||||
headingElt.insertBefore(prefixElt, headingElt.firstChild);
|
|
||||||
// 将新的 <span> 元素替换原始元素
|
|
||||||
headingElt.appendChild(contentElt);
|
|
||||||
const suffixElt = document.createElement('span');
|
|
||||||
suffixElt.className = 'suffix';
|
|
||||||
headingElt.appendChild(suffixElt);
|
|
||||||
}
|
}
|
||||||
if (insertBeforeTocElt) {
|
if (insertBeforeTocElt) {
|
||||||
this.tocElt.insertBefore(sectionTocElt, insertBeforeTocElt);
|
this.tocElt.insertBefore(sectionTocElt, insertBeforeTocElt);
|
||||||
@ -453,13 +438,6 @@ const editorSvc = Object.assign(new Vue(), editorSvcDiscussions, editorSvcUtils,
|
|||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
this.pagedownEditor.hooks.set('insertChatGptDialog', (callback) => {
|
|
||||||
store.dispatch('modal/open', {
|
|
||||||
type: 'chatGpt',
|
|
||||||
callback,
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
this.pagedownEditor.hooks.set('insertImageUploading', (callback) => {
|
this.pagedownEditor.hooks.set('insertImageUploading', (callback) => {
|
||||||
callback(store.getters['img/currImgId']);
|
callback(store.getters['img/currImgId']);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import md5 from 'js-md5';
|
|
||||||
import FileSaver from 'file-saver';
|
import FileSaver from 'file-saver';
|
||||||
import TemplateWorker from 'worker-loader!./templateWorker.js'; // eslint-disable-line
|
import TemplateWorker from 'worker-loader!./templateWorker.js'; // eslint-disable-line
|
||||||
import localDbSvc from './localDbSvc';
|
import localDbSvc from './localDbSvc';
|
||||||
@ -35,24 +34,6 @@ function groupHeadings(headings, level = 1) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getImgBase64 = async (uri) => {
|
|
||||||
if (uri.indexOf('http://') !== 0 && uri.indexOf('https://') !== 0) {
|
|
||||||
const currDirNode = store.getters['explorer/selectedNodeFolder'];
|
|
||||||
const absoluteImgPath = utils.getAbsoluteFilePath(currDirNode, uri);
|
|
||||||
const md5Id = md5(absoluteImgPath);
|
|
||||||
const imgItem = await localDbSvc.getImgItem(md5Id);
|
|
||||||
if (imgItem) {
|
|
||||||
const potIdx = uri.lastIndexOf('.');
|
|
||||||
const suffix = potIdx > -1 ? uri.substring(potIdx + 1) : 'png';
|
|
||||||
const mime = `image/${suffix}`;
|
|
||||||
return `data:${mime};base64,${imgItem.content}`;
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return uri;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const containerElt = document.createElement('div');
|
const containerElt = document.createElement('div');
|
||||||
containerElt.className = 'hidden-rendering-container';
|
containerElt.className = 'hidden-rendering-container';
|
||||||
document.body.appendChild(containerElt);
|
document.body.appendChild(containerElt);
|
||||||
@ -73,13 +54,6 @@ export default {
|
|||||||
const parsingCtx = markdownConversionSvc.parseSections(converter, content.text);
|
const parsingCtx = markdownConversionSvc.parseSections(converter, content.text);
|
||||||
const conversionCtx = markdownConversionSvc.convert(parsingCtx);
|
const conversionCtx = markdownConversionSvc.convert(parsingCtx);
|
||||||
const html = conversionCtx.htmlSectionList.map(htmlSanitizer.sanitizeHtml).join('');
|
const html = conversionCtx.htmlSectionList.map(htmlSanitizer.sanitizeHtml).join('');
|
||||||
const colorThemeClass = `app--${store.getters['data/computedSettings'].colorTheme}`;
|
|
||||||
const themeClass = `preview-theme--${store.state.theme.currPreviewTheme}`;
|
|
||||||
let themeStyleContent = '';
|
|
||||||
const themeStyleEle = document.getElementById(`preview-theme-${store.state.theme.currPreviewTheme}`);
|
|
||||||
if (themeStyleEle) {
|
|
||||||
themeStyleContent = themeStyleEle.innerText;
|
|
||||||
}
|
|
||||||
containerElt.innerHTML = html;
|
containerElt.innerHTML = html;
|
||||||
extensionSvc.sectionPreview(containerElt, options);
|
extensionSvc.sectionPreview(containerElt, options);
|
||||||
|
|
||||||
@ -91,48 +65,8 @@ export default {
|
|||||||
wrapperElt.parentNode.removeChild(wrapperElt);
|
wrapperElt.parentNode.removeChild(wrapperElt);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 替换相对路径图片为blob图片
|
|
||||||
const imgs = Array.prototype.slice.call(containerElt.getElementsByTagName('img')).map((imgElt) => {
|
|
||||||
let uri = imgElt.attributes && imgElt.attributes.src && imgElt.attributes.src.nodeValue;
|
|
||||||
if (uri && uri.indexOf('http://') !== 0 && uri.indexOf('https://') !== 0) {
|
|
||||||
uri = decodeURIComponent(uri);
|
|
||||||
imgElt.removeAttribute('src');
|
|
||||||
return { imgElt, uri };
|
|
||||||
}
|
|
||||||
return { imgElt };
|
|
||||||
});
|
|
||||||
const loadedPromises = imgs.map(it => new Promise((resolve, reject) => {
|
|
||||||
if (!it.imgElt.src && it.uri) {
|
|
||||||
getImgBase64(it.uri).then((newUrl) => {
|
|
||||||
it.imgElt.src = newUrl;
|
|
||||||
resolve();
|
|
||||||
}, () => reject(new Error('加载当前空间图片出错')));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
}));
|
|
||||||
await Promise.all(loadedPromises);
|
|
||||||
|
|
||||||
// Make TOC
|
// Make TOC
|
||||||
const allHeaders = containerElt.querySelectorAll('h1,h2,h3,h4,h5,h6');
|
const headings = containerElt.querySelectorAll('h1,h2,h3,h4,h5,h6').cl_map(headingElt => ({
|
||||||
Array.prototype.slice.call(allHeaders).forEach((headingElt) => {
|
|
||||||
// 创建一个新的 <span> 元素
|
|
||||||
const contentElt = document.createElement('span');
|
|
||||||
contentElt.className = 'content';
|
|
||||||
// 将原始内容移动到新的 <span> 元素中
|
|
||||||
while (headingElt.firstChild) {
|
|
||||||
contentElt.appendChild(headingElt.firstChild);
|
|
||||||
}
|
|
||||||
const prefixElt = document.createElement('span');
|
|
||||||
prefixElt.className = 'prefix';
|
|
||||||
headingElt.insertBefore(prefixElt, headingElt.firstChild);
|
|
||||||
// 将新的 <span> 元素替换原始元素
|
|
||||||
headingElt.appendChild(contentElt);
|
|
||||||
const suffixElt = document.createElement('span');
|
|
||||||
suffixElt.className = 'suffix';
|
|
||||||
headingElt.appendChild(suffixElt);
|
|
||||||
});
|
|
||||||
const headings = allHeaders.cl_map(headingElt => ({
|
|
||||||
title: headingElt.textContent,
|
title: headingElt.textContent,
|
||||||
anchor: headingElt.id,
|
anchor: headingElt.id,
|
||||||
level: parseInt(headingElt.tagName.slice(1), 10),
|
level: parseInt(headingElt.tagName.slice(1), 10),
|
||||||
@ -149,9 +83,6 @@ export default {
|
|||||||
yamlProperties: content.properties,
|
yamlProperties: content.properties,
|
||||||
html: containerElt.innerHTML,
|
html: containerElt.innerHTML,
|
||||||
toc,
|
toc,
|
||||||
colorThemeClass,
|
|
||||||
themeClass,
|
|
||||||
themeStyleContent,
|
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
@ -44,7 +44,7 @@ const noSpellcheckTokens = Object.create(null);
|
|||||||
[
|
[
|
||||||
'code',
|
'code',
|
||||||
'pre',
|
'pre',
|
||||||
'pre gfm cn-code',
|
'pre gfm',
|
||||||
'math block',
|
'math block',
|
||||||
'math inline',
|
'math inline',
|
||||||
'math expr block',
|
'math expr block',
|
||||||
|
@ -3,8 +3,8 @@ import store from '../../store';
|
|||||||
import editorSvc from '../../services/editorSvc';
|
import editorSvc from '../../services/editorSvc';
|
||||||
import syncSvc from '../../services/syncSvc';
|
import syncSvc from '../../services/syncSvc';
|
||||||
|
|
||||||
// Skip shortcuts if modal is open
|
// Skip shortcuts if modal is open or editor is hidden
|
||||||
Mousetrap.prototype.stopCallback = () => store.getters['modal/config'];
|
Mousetrap.prototype.stopCallback = () => store.getters['modal/config'] || !store.getters['content/isCurrentEditable'];
|
||||||
|
|
||||||
const pagedownHandler = name => () => {
|
const pagedownHandler = name => () => {
|
||||||
editorSvc.pagedownEditor.uiManager.doClick(name);
|
editorSvc.pagedownEditor.uiManager.doClick(name);
|
||||||
@ -20,14 +20,6 @@ const findReplaceOpener = type => () => {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleEditor = () => () => {
|
|
||||||
store.dispatch('data/toggleEditor', !store.getters['data/layoutSettings'].showEditor);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 非编辑模式下支持的快捷键
|
|
||||||
const noEditableShortcutMethods = ['toggleeditor'];
|
|
||||||
|
|
||||||
const methods = {
|
const methods = {
|
||||||
bold: pagedownHandler('bold'),
|
bold: pagedownHandler('bold'),
|
||||||
italic: pagedownHandler('italic'),
|
italic: pagedownHandler('italic'),
|
||||||
@ -36,7 +28,6 @@ const methods = {
|
|||||||
quote: pagedownHandler('quote'),
|
quote: pagedownHandler('quote'),
|
||||||
code: pagedownHandler('code'),
|
code: pagedownHandler('code'),
|
||||||
image: pagedownHandler('image'),
|
image: pagedownHandler('image'),
|
||||||
chatgpt: pagedownHandler('chatgpt'),
|
|
||||||
olist: pagedownHandler('olist'),
|
olist: pagedownHandler('olist'),
|
||||||
ulist: pagedownHandler('ulist'),
|
ulist: pagedownHandler('ulist'),
|
||||||
clist: pagedownHandler('clist'),
|
clist: pagedownHandler('clist'),
|
||||||
@ -44,7 +35,6 @@ const methods = {
|
|||||||
inline: pagedownHandler('heading'),
|
inline: pagedownHandler('heading'),
|
||||||
hr: pagedownHandler('hr'),
|
hr: pagedownHandler('hr'),
|
||||||
inlineformula: pagedownHandler('inlineformula'),
|
inlineformula: pagedownHandler('inlineformula'),
|
||||||
toggleeditor: toggleEditor(),
|
|
||||||
sync() {
|
sync() {
|
||||||
if (syncSvc.isSyncPossible()) {
|
if (syncSvc.isSyncPossible()) {
|
||||||
syncSvc.requestSync();
|
syncSvc.requestSync();
|
||||||
@ -76,11 +66,8 @@ const methods = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
store.watch(
|
store.watch(
|
||||||
() => ({
|
() => store.getters['data/computedSettings'],
|
||||||
computedSettings: store.getters['data/computedSettings'],
|
(computedSettings) => {
|
||||||
isCurrentEditable: store.getters['content/isCurrentEditable'],
|
|
||||||
}),
|
|
||||||
({ computedSettings, isCurrentEditable }) => {
|
|
||||||
Mousetrap.reset();
|
Mousetrap.reset();
|
||||||
|
|
||||||
Object.entries(computedSettings.shortcuts).forEach(([key, shortcut]) => {
|
Object.entries(computedSettings.shortcuts).forEach(([key, shortcut]) => {
|
||||||
@ -92,18 +79,14 @@ store.watch(
|
|||||||
}
|
}
|
||||||
if (Object.prototype.hasOwnProperty.call(methods, method)) {
|
if (Object.prototype.hasOwnProperty.call(methods, method)) {
|
||||||
try {
|
try {
|
||||||
// editor is editable or 一些非编辑模式下支持的快捷键
|
Mousetrap.bind(`${key}`, () => !methods[method].apply(null, params));
|
||||||
if (isCurrentEditable || noEditableShortcutMethods.indexOf(method) !== -1) {
|
|
||||||
Mousetrap.bind(`${key}`, () => !methods[method].apply(null, params));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Ignore
|
// Ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
immediate: true,
|
immediate: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -36,7 +36,7 @@ export default new Provider({
|
|||||||
async uploadContent(token, content, syncLocation) {
|
async uploadContent(token, content, syncLocation) {
|
||||||
const updatedSyncLocation = {
|
const updatedSyncLocation = {
|
||||||
...syncLocation,
|
...syncLocation,
|
||||||
projectId: await giteaHelper.getProjectId(token, syncLocation),
|
projectId: await giteaHelper.getProjectId(syncLocation),
|
||||||
};
|
};
|
||||||
if (!savedSha[updatedSyncLocation.id]) {
|
if (!savedSha[updatedSyncLocation.id]) {
|
||||||
try {
|
try {
|
||||||
@ -59,7 +59,7 @@ export default new Provider({
|
|||||||
async publish(token, html, metadata, publishLocation, commitMessage) {
|
async publish(token, html, metadata, publishLocation, commitMessage) {
|
||||||
const updatedPublishLocation = {
|
const updatedPublishLocation = {
|
||||||
...publishLocation,
|
...publishLocation,
|
||||||
projectId: await giteaHelper.getProjectId(token, publishLocation),
|
projectId: await giteaHelper.getProjectId(publishLocation),
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
// Get the last sha
|
// Get the last sha
|
||||||
@ -81,7 +81,7 @@ export default new Provider({
|
|||||||
async openFile(token, syncLocation) {
|
async openFile(token, syncLocation) {
|
||||||
const updatedSyncLocation = {
|
const updatedSyncLocation = {
|
||||||
...syncLocation,
|
...syncLocation,
|
||||||
projectId: await giteaHelper.getProjectId(token, syncLocation),
|
projectId: await giteaHelper.getProjectId(syncLocation),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if the file exists and open it
|
// Check if the file exists and open it
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
import store from '../../store';
|
|
||||||
import giteeHelper from './helpers/giteeHelper';
|
|
||||||
import Provider from './common/Provider';
|
|
||||||
import utils from '../utils';
|
|
||||||
import userSvc from '../userSvc';
|
|
||||||
|
|
||||||
export default new Provider({
|
|
||||||
id: 'giteegist',
|
|
||||||
name: 'GiteeGist',
|
|
||||||
getToken({ sub }) {
|
|
||||||
return store.getters['data/giteeTokensBySub'][sub];
|
|
||||||
},
|
|
||||||
getLocationUrl({ gistId }) {
|
|
||||||
return `https://gitee.com/caojiezi2003/codes/${gistId}`;
|
|
||||||
},
|
|
||||||
getLocationDescription({ filename }) {
|
|
||||||
return filename;
|
|
||||||
},
|
|
||||||
async downloadContent(token, syncLocation) {
|
|
||||||
const content = await giteeHelper.downloadGist({
|
|
||||||
...syncLocation,
|
|
||||||
token,
|
|
||||||
});
|
|
||||||
return Provider.parseContent(content, `${syncLocation.fileId}/content`);
|
|
||||||
},
|
|
||||||
async uploadContent(token, content, syncLocation) {
|
|
||||||
const file = store.state.file.itemsById[syncLocation.fileId];
|
|
||||||
const description = utils.sanitizeName(file && file.name);
|
|
||||||
const gist = await giteeHelper.uploadGist({
|
|
||||||
...syncLocation,
|
|
||||||
token,
|
|
||||||
description,
|
|
||||||
content: Provider.serializeContent(content),
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
...syncLocation,
|
|
||||||
gistId: gist.id,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async publish(token, html, metadata, publishLocation) {
|
|
||||||
const gist = await giteeHelper.uploadGist({
|
|
||||||
...publishLocation,
|
|
||||||
token,
|
|
||||||
description: metadata.title,
|
|
||||||
content: html,
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
...publishLocation,
|
|
||||||
gistId: gist.id,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
makeLocation(token, filename, isPublic, gistId) {
|
|
||||||
return {
|
|
||||||
providerId: this.id,
|
|
||||||
sub: token.sub,
|
|
||||||
filename,
|
|
||||||
isPublic,
|
|
||||||
gistId,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async listFileRevisions({ token, syncLocation }) {
|
|
||||||
const entries = await giteeHelper.getGistCommits({
|
|
||||||
...syncLocation,
|
|
||||||
token,
|
|
||||||
});
|
|
||||||
|
|
||||||
return entries.map((entry) => {
|
|
||||||
const sub = `${giteeHelper.subPrefix}:${entry.user.id}`;
|
|
||||||
userSvc.addUserInfo({ id: sub, name: entry.user.login, imageUrl: entry.user.avatar_url });
|
|
||||||
return {
|
|
||||||
sub,
|
|
||||||
id: entry.version,
|
|
||||||
message: entry.commit && entry.commit.message,
|
|
||||||
created: new Date(entry.committed_at).getTime(),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
async loadFileRevision() {
|
|
||||||
// Revision are already loaded
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
// async getFileRevisionContent({
|
|
||||||
// token,
|
|
||||||
// contentId,
|
|
||||||
// syncLocation,
|
|
||||||
// revisionId,
|
|
||||||
// }) {
|
|
||||||
// const data = await giteeHelper.downloadGistRevision({
|
|
||||||
// ...syncLocation,
|
|
||||||
// token,
|
|
||||||
// sha: revisionId,
|
|
||||||
// });
|
|
||||||
// return Provider.parseContent(data, contentId);
|
|
||||||
// },
|
|
||||||
});
|
|
@ -1,292 +0,0 @@
|
|||||||
import store from '../../store';
|
|
||||||
import githubHelper from './helpers/githubHelper';
|
|
||||||
import Provider from './common/Provider';
|
|
||||||
import gitWorkspaceSvc from '../gitWorkspaceSvc';
|
|
||||||
import userSvc from '../userSvc';
|
|
||||||
|
|
||||||
const appDataRepo = 'stackedit-app-data';
|
|
||||||
const appDataBranch = 'master';
|
|
||||||
|
|
||||||
export default new Provider({
|
|
||||||
id: 'githubAppData',
|
|
||||||
name: 'Gitee应用数据',
|
|
||||||
getToken() {
|
|
||||||
return store.getters['workspace/syncToken'];
|
|
||||||
},
|
|
||||||
getWorkspaceParams() {
|
|
||||||
// No param as it's the main workspace
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
getWorkspaceLocationUrl() {
|
|
||||||
// No direct link to app data
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
getSyncDataUrl() {
|
|
||||||
// No direct link to app data
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
getSyncDataDescription({ id }) {
|
|
||||||
return id;
|
|
||||||
},
|
|
||||||
async initWorkspace() {
|
|
||||||
// Nothing much to do since the main workspace isn't necessarily synchronized
|
|
||||||
// Return the main workspace
|
|
||||||
return store.getters['workspace/workspacesById'].main;
|
|
||||||
},
|
|
||||||
getChanges() {
|
|
||||||
const token = this.getToken();
|
|
||||||
return githubHelper.getTree({
|
|
||||||
owner: token.name,
|
|
||||||
repo: appDataRepo,
|
|
||||||
branch: appDataBranch,
|
|
||||||
token,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
prepareChanges(tree) {
|
|
||||||
return gitWorkspaceSvc.makeChanges(tree);
|
|
||||||
},
|
|
||||||
async saveWorkspaceItem({ item }) {
|
|
||||||
const syncData = {
|
|
||||||
id: store.getters.gitPathsByItemId[item.id],
|
|
||||||
type: item.type,
|
|
||||||
hash: item.hash,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Files and folders are not in git, only contents
|
|
||||||
if (item.type === 'file' || item.type === 'folder') {
|
|
||||||
return { syncData };
|
|
||||||
}
|
|
||||||
|
|
||||||
// locations are stored as paths, so we upload an empty file
|
|
||||||
const syncToken = store.getters['workspace/syncToken'];
|
|
||||||
await githubHelper.uploadFile({
|
|
||||||
owner: syncToken.name,
|
|
||||||
repo: appDataRepo,
|
|
||||||
branch: appDataBranch,
|
|
||||||
token: syncToken,
|
|
||||||
path: syncData.id,
|
|
||||||
content: '',
|
|
||||||
sha: gitWorkspaceSvc.shaByPath[syncData.id],
|
|
||||||
commitMessage: item.commitMessage,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Return sync data to save
|
|
||||||
return { syncData };
|
|
||||||
},
|
|
||||||
async removeWorkspaceItem({ syncData }) {
|
|
||||||
if (gitWorkspaceSvc.shaByPath[syncData.id]) {
|
|
||||||
const syncToken = store.getters['workspace/syncToken'];
|
|
||||||
await githubHelper.removeFile({
|
|
||||||
owner: syncToken.name,
|
|
||||||
repo: appDataRepo,
|
|
||||||
branch: appDataBranch,
|
|
||||||
token: syncToken,
|
|
||||||
path: syncData.id,
|
|
||||||
sha: gitWorkspaceSvc.shaByPath[syncData.id],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async downloadWorkspaceContent({
|
|
||||||
token,
|
|
||||||
contentId,
|
|
||||||
contentSyncData,
|
|
||||||
fileSyncData,
|
|
||||||
}) {
|
|
||||||
const { sha, data } = await githubHelper.downloadFile({
|
|
||||||
owner: token.name,
|
|
||||||
repo: appDataRepo,
|
|
||||||
branch: appDataBranch,
|
|
||||||
token,
|
|
||||||
path: fileSyncData.id,
|
|
||||||
});
|
|
||||||
gitWorkspaceSvc.shaByPath[fileSyncData.id] = sha;
|
|
||||||
const content = Provider.parseContent(data, contentId);
|
|
||||||
return {
|
|
||||||
content,
|
|
||||||
contentSyncData: {
|
|
||||||
...contentSyncData,
|
|
||||||
hash: content.hash,
|
|
||||||
sha,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async downloadFile({ token, path }) {
|
|
||||||
const { sha, data } = await githubHelper.downloadFile({
|
|
||||||
owner: token.name,
|
|
||||||
repo: appDataRepo,
|
|
||||||
branch: appDataBranch,
|
|
||||||
token,
|
|
||||||
path,
|
|
||||||
isImg: true,
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
content: data,
|
|
||||||
sha,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async downloadWorkspaceData({ token, syncData }) {
|
|
||||||
if (!syncData) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const path = `.stackedit-data/${syncData.id}.json`;
|
|
||||||
// const path = store.getters.gitPathsByItemId[syncData.id];
|
|
||||||
// const path = syncData.id;
|
|
||||||
const { sha, data } = await githubHelper.downloadFile({
|
|
||||||
owner: token.name,
|
|
||||||
repo: appDataRepo,
|
|
||||||
branch: appDataBranch,
|
|
||||||
token,
|
|
||||||
path,
|
|
||||||
});
|
|
||||||
if (!sha) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
gitWorkspaceSvc.shaByPath[path] = sha;
|
|
||||||
const item = JSON.parse(data);
|
|
||||||
return {
|
|
||||||
item,
|
|
||||||
syncData: {
|
|
||||||
...syncData,
|
|
||||||
hash: item.hash,
|
|
||||||
sha,
|
|
||||||
type: 'data',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async uploadWorkspaceContent({
|
|
||||||
token,
|
|
||||||
content,
|
|
||||||
file,
|
|
||||||
commitMessage,
|
|
||||||
}) {
|
|
||||||
const isImg = file.type === 'img';
|
|
||||||
const path = !isImg ? store.getters.gitPathsByItemId[file.id] : file.path;
|
|
||||||
const res = await githubHelper.uploadFile({
|
|
||||||
owner: token.name,
|
|
||||||
repo: appDataRepo,
|
|
||||||
branch: appDataBranch,
|
|
||||||
token,
|
|
||||||
path,
|
|
||||||
content: !isImg ? Provider.serializeContent(content) : file.content,
|
|
||||||
sha: gitWorkspaceSvc.shaByPath[!isImg ? path : file.path],
|
|
||||||
isImg,
|
|
||||||
commitMessage,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isImg) {
|
|
||||||
return {
|
|
||||||
sha: res.content.sha,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// Return new sync data
|
|
||||||
return {
|
|
||||||
contentSyncData: {
|
|
||||||
id: store.getters.gitPathsByItemId[content.id],
|
|
||||||
type: content.type,
|
|
||||||
hash: content.hash,
|
|
||||||
sha: res.content.sha,
|
|
||||||
},
|
|
||||||
fileSyncData: {
|
|
||||||
id: path,
|
|
||||||
type: 'file',
|
|
||||||
hash: file.hash,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async uploadWorkspaceData({
|
|
||||||
token,
|
|
||||||
item,
|
|
||||||
syncData,
|
|
||||||
}) {
|
|
||||||
const path = `.stackedit-data/${item.id}.json`;
|
|
||||||
// const path = store.getters.gitPathsByItemId[item.id];
|
|
||||||
// const path = syncData.id;
|
|
||||||
const res = await githubHelper.uploadFile({
|
|
||||||
token,
|
|
||||||
owner: token.name,
|
|
||||||
repo: appDataRepo,
|
|
||||||
branch: appDataBranch,
|
|
||||||
path,
|
|
||||||
content: JSON.stringify(item),
|
|
||||||
sha: gitWorkspaceSvc.shaByPath[path],
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
syncData: {
|
|
||||||
...syncData,
|
|
||||||
type: item.type,
|
|
||||||
hash: item.hash,
|
|
||||||
data: item.data,
|
|
||||||
sha: res.content.sha,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async listFileRevisions({ token, fileSyncDataId }) {
|
|
||||||
const { owner, repo, branch } = {
|
|
||||||
owner: token.name,
|
|
||||||
repo: appDataRepo,
|
|
||||||
branch: appDataBranch,
|
|
||||||
};
|
|
||||||
const entries = await githubHelper.getCommits({
|
|
||||||
token,
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
sha: branch,
|
|
||||||
path: fileSyncDataId,
|
|
||||||
});
|
|
||||||
|
|
||||||
return entries.map(({
|
|
||||||
author,
|
|
||||||
committer,
|
|
||||||
commit,
|
|
||||||
sha,
|
|
||||||
}) => {
|
|
||||||
let user;
|
|
||||||
if (author && author.login) {
|
|
||||||
user = author;
|
|
||||||
} else if (committer && committer.login) {
|
|
||||||
user = committer;
|
|
||||||
}
|
|
||||||
const sub = `${githubHelper.subPrefix}:${user.login}`;
|
|
||||||
if (user.avatar_url && user.avatar_url.endsWith('.png') && !user.avatar_url.endsWith('no_portrait.png')) {
|
|
||||||
user.avatar_url = `${user.avatar_url}!avatar60`;
|
|
||||||
}
|
|
||||||
userSvc.addUserInfo({ id: sub, name: user.login, imageUrl: user.avatar_url });
|
|
||||||
const date = (commit.author && commit.author.date)
|
|
||||||
|| (commit.committer && commit.committer.date)
|
|
||||||
|| 1;
|
|
||||||
return {
|
|
||||||
id: sha,
|
|
||||||
sub,
|
|
||||||
message: commit.message,
|
|
||||||
created: new Date(date).getTime(),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
async loadFileRevision() {
|
|
||||||
// Revisions are already loaded
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
async getFileRevisionContent({
|
|
||||||
token,
|
|
||||||
contentId,
|
|
||||||
fileSyncDataId,
|
|
||||||
revisionId,
|
|
||||||
}) {
|
|
||||||
const { data } = await githubHelper.downloadFile({
|
|
||||||
owner: token.name,
|
|
||||||
repo: appDataRepo,
|
|
||||||
branch: revisionId,
|
|
||||||
token,
|
|
||||||
path: fileSyncDataId,
|
|
||||||
});
|
|
||||||
return Provider.parseContent(data, contentId);
|
|
||||||
},
|
|
||||||
getFilePathUrl(path) {
|
|
||||||
const token = this.getToken();
|
|
||||||
if (!token) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return `https://github.com/${token.name}/${appDataRepo}/blob/${appDataBranch}${path}`;
|
|
||||||
},
|
|
||||||
});
|
|
@ -75,11 +75,11 @@ export default new Provider({
|
|||||||
const sub = workspace ? workspace.sub : utils.queryParams.sub;
|
const sub = workspace ? workspace.sub : utils.queryParams.sub;
|
||||||
let token = store.getters['data/gitlabTokensBySub'][sub];
|
let token = store.getters['data/gitlabTokensBySub'][sub];
|
||||||
if (!token) {
|
if (!token) {
|
||||||
const { applicationId, applicationSecret } = await store.dispatch('modal/open', {
|
const { applicationId } = await store.dispatch('modal/open', {
|
||||||
type: 'gitlabAccount',
|
type: 'gitlabAccount',
|
||||||
forceServerUrl: serverUrl,
|
forceServerUrl: serverUrl,
|
||||||
});
|
});
|
||||||
token = await gitlabHelper.addAccount(serverUrl, applicationId, applicationSecret, sub);
|
token = await gitlabHelper.addAccount(serverUrl, applicationId, sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!workspace) {
|
if (!workspace) {
|
||||||
@ -173,18 +173,6 @@ export default new Provider({
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async downloadFile({ token, path }) {
|
|
||||||
const { sha, data } = await gitlabHelper.downloadFile({
|
|
||||||
...store.getters['workspace/currentWorkspace'],
|
|
||||||
token,
|
|
||||||
path,
|
|
||||||
isImg: true,
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
content: data,
|
|
||||||
sha,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async downloadWorkspaceData({ token, syncData }) {
|
async downloadWorkspaceData({ token, syncData }) {
|
||||||
if (!syncData) {
|
if (!syncData) {
|
||||||
return {};
|
return {};
|
||||||
@ -212,27 +200,18 @@ export default new Provider({
|
|||||||
file,
|
file,
|
||||||
commitMessage,
|
commitMessage,
|
||||||
}) {
|
}) {
|
||||||
const isImg = file.type === 'img';
|
|
||||||
const path = store.getters.gitPathsByItemId[file.id];
|
const path = store.getters.gitPathsByItemId[file.id];
|
||||||
const absolutePath = !isImg ? `${store.getters['workspace/currentWorkspace'].path || ''}${path}` : file.path;
|
const absolutePath = `${store.getters['workspace/currentWorkspace'].path || ''}${path}`;
|
||||||
const sha = gitWorkspaceSvc.shaByPath[!isImg ? path : file.path];
|
const sha = gitWorkspaceSvc.shaByPath[path];
|
||||||
await gitlabHelper.uploadFile({
|
await gitlabHelper.uploadFile({
|
||||||
...store.getters['workspace/currentWorkspace'],
|
...store.getters['workspace/currentWorkspace'],
|
||||||
token,
|
token,
|
||||||
path: absolutePath,
|
path: absolutePath,
|
||||||
content: !isImg ? Provider.serializeContent(content) : file.content,
|
content: Provider.serializeContent(content),
|
||||||
sha,
|
sha,
|
||||||
isImg,
|
|
||||||
commitMessage,
|
commitMessage,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isImg) {
|
|
||||||
const res2 = await this.downloadFile({ token, path: absolutePath });
|
|
||||||
return {
|
|
||||||
sha: res2.sha,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return new sync data
|
// Return new sync data
|
||||||
return {
|
return {
|
||||||
contentSyncData: {
|
contentSyncData: {
|
||||||
|
@ -317,12 +317,6 @@ export default {
|
|||||||
isImg,
|
isImg,
|
||||||
commitMessage,
|
commitMessage,
|
||||||
}) {
|
}) {
|
||||||
// 非法的文件名 不让提交
|
|
||||||
if (!path || path.endsWith('undefined')) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
resolve({ res: { content: { sha: null } } });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let uploadContent = content;
|
let uploadContent = content;
|
||||||
if (isImg && typeof content !== 'string') {
|
if (isImg && typeof content !== 'string') {
|
||||||
uploadContent = await utils.encodeFiletoBase64(content);
|
uploadContent = await utils.encodeFiletoBase64(content);
|
||||||
|
@ -147,7 +147,6 @@ export default {
|
|||||||
sub: `${user.login}`,
|
sub: `${user.login}`,
|
||||||
};
|
};
|
||||||
if (isMain) {
|
if (isMain) {
|
||||||
token.providerId = 'giteeAppData';
|
|
||||||
// 检查 stackedit-app-data 仓库是否已经存在 如果不存在则创建该仓库
|
// 检查 stackedit-app-data 仓库是否已经存在 如果不存在则创建该仓库
|
||||||
await this.checkAndCreateRepo(token);
|
await this.checkAndCreateRepo(token);
|
||||||
}
|
}
|
||||||
@ -280,12 +279,6 @@ export default {
|
|||||||
isImg,
|
isImg,
|
||||||
commitMessage,
|
commitMessage,
|
||||||
}) {
|
}) {
|
||||||
// 非法的文件名 不让提交
|
|
||||||
if (!path || path.endsWith('undefined')) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
resolve({ res: { content: { sha: null } } });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let uploadContent = content;
|
let uploadContent = content;
|
||||||
if (isImg && typeof content !== 'string') {
|
if (isImg && typeof content !== 'string') {
|
||||||
uploadContent = await utils.encodeFiletoBase64(content);
|
uploadContent = await utils.encodeFiletoBase64(content);
|
||||||
@ -353,8 +346,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://gitee.com/api/v5/swagger#/postV5Gists
|
* https://developer.gitee.com/v3/gists/#create-a-gist
|
||||||
* https://gitee.com/api/v5/swagger#/patchV5GistsId
|
* https://developer.gitee.com/v3/gists/#edit-a-gist
|
||||||
*/
|
*/
|
||||||
async uploadGist({
|
async uploadGist({
|
||||||
token,
|
token,
|
||||||
@ -364,7 +357,8 @@ export default {
|
|||||||
isPublic,
|
isPublic,
|
||||||
gistId,
|
gistId,
|
||||||
}) {
|
}) {
|
||||||
const { body } = await request(token, gistId ? {
|
const refreshedToken = await this.refreshToken(token);
|
||||||
|
const { body } = await request(refreshedToken, gistId ? {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
url: `https://gitee.com/api/v5/gists/${gistId}`,
|
url: `https://gitee.com/api/v5/gists/${gistId}`,
|
||||||
body: {
|
body: {
|
||||||
@ -392,15 +386,16 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://gitee.com/api/v5/swagger#/getV5Gists
|
* https://developer.gitee.com/v3/gists/#get-a-single-gist
|
||||||
*/
|
*/
|
||||||
async downloadGist({
|
async downloadGist({
|
||||||
token,
|
token,
|
||||||
gistId,
|
gistId,
|
||||||
filename,
|
filename,
|
||||||
}) {
|
}) {
|
||||||
const result = (await request(token, {
|
const refreshedToken = await this.refreshToken(token);
|
||||||
url: `https://api.github.com/gists/${gistId}`,
|
const result = (await request(refreshedToken, {
|
||||||
|
url: `https://gitee.com/api/v5/gists/${gistId}`,
|
||||||
})).body.files[filename];
|
})).body.files[filename];
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw new Error('Gist file not found.');
|
throw new Error('Gist file not found.');
|
||||||
@ -409,15 +404,35 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://gitee.com/api/v5/swagger#/getV5GistsIdCommits
|
* https://developer.gitee.com/v3/gists/#list-gist-commits
|
||||||
*/
|
*/
|
||||||
async getGistCommits({
|
async getGistCommits({
|
||||||
token,
|
token,
|
||||||
gistId,
|
gistId,
|
||||||
}) {
|
}) {
|
||||||
const { body } = await request(token, {
|
const refreshedToken = await this.refreshToken(token);
|
||||||
|
const { body } = await request(refreshedToken, {
|
||||||
url: `https://gitee.com/api/v5/gists/${gistId}/commits`,
|
url: `https://gitee.com/api/v5/gists/${gistId}/commits`,
|
||||||
});
|
});
|
||||||
return body;
|
return body;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://developer.gitee.com/v3/gists/#get-a-specific-revision-of-a-gist
|
||||||
|
*/
|
||||||
|
async downloadGistRevision({
|
||||||
|
token,
|
||||||
|
gistId,
|
||||||
|
filename,
|
||||||
|
sha,
|
||||||
|
}) {
|
||||||
|
const refreshedToken = await this.refreshToken(token);
|
||||||
|
const result = (await request(refreshedToken, {
|
||||||
|
url: `https://gitee.com/api/v5/gists/${gistId}/${sha}`,
|
||||||
|
})).body.files[filename];
|
||||||
|
if (!result) {
|
||||||
|
throw new Error('Gist file not found.');
|
||||||
|
}
|
||||||
|
return result.content;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -6,8 +6,6 @@ import badgeSvc from '../../badgeSvc';
|
|||||||
|
|
||||||
const getScopes = token => [token.repoFullAccess ? 'repo' : 'public_repo', 'gist'];
|
const getScopes = token => [token.repoFullAccess ? 'repo' : 'public_repo', 'gist'];
|
||||||
|
|
||||||
const appDataRepo = 'stackedit-app-data';
|
|
||||||
|
|
||||||
const request = (token, options) => networkSvc.request({
|
const request = (token, options) => networkSvc.request({
|
||||||
...options,
|
...options,
|
||||||
headers: {
|
headers: {
|
||||||
@ -64,7 +62,7 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* https://developer.github.com/apps/building-oauth-apps/authorization-options-for-oauth-apps/
|
* https://developer.github.com/apps/building-oauth-apps/authorization-options-for-oauth-apps/
|
||||||
*/
|
*/
|
||||||
async startOauth2(scopes, sub = null, silent = false, isMain) {
|
async startOauth2(scopes, sub = null, silent = false) {
|
||||||
await networkSvc.getServerConf();
|
await networkSvc.getServerConf();
|
||||||
const clientId = store.getters['data/serverConf'].githubClientId;
|
const clientId = store.getters['data/serverConf'].githubClientId;
|
||||||
|
|
||||||
@ -112,26 +110,16 @@ export default {
|
|||||||
const token = {
|
const token = {
|
||||||
scopes,
|
scopes,
|
||||||
accessToken,
|
accessToken,
|
||||||
// 主文档空间的登录 标识登录
|
|
||||||
isLogin: !!isMain || (oldToken && !!oldToken.isLogin),
|
|
||||||
name: user.login,
|
name: user.login,
|
||||||
sub: `${user.id}`,
|
sub: `${user.id}`,
|
||||||
imgStorages: oldToken && oldToken.imgStorages,
|
imgStorages: oldToken && oldToken.imgStorages,
|
||||||
repoFullAccess: scopes.includes('repo'),
|
repoFullAccess: scopes.includes('repo'),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isMain) {
|
|
||||||
token.providerId = 'githubAppData';
|
|
||||||
// check stackedit-app-data repo exist?
|
|
||||||
await this.checkAndCreateRepo(token);
|
|
||||||
}
|
|
||||||
// Add token to github tokens
|
// Add token to github tokens
|
||||||
store.dispatch('data/addGithubToken', token);
|
store.dispatch('data/addGithubToken', token);
|
||||||
return token;
|
return token;
|
||||||
},
|
},
|
||||||
signin() {
|
|
||||||
return this.startOauth2(['repo', 'gist'], null, false, true);
|
|
||||||
},
|
|
||||||
async addAccount(repoFullAccess = false) {
|
async addAccount(repoFullAccess = false) {
|
||||||
const token = await this.startOauth2(getScopes({ repoFullAccess }));
|
const token = await this.startOauth2(getScopes({ repoFullAccess }));
|
||||||
badgeSvc.addBadge('addGitHubAccount');
|
badgeSvc.addBadge('addGitHubAccount');
|
||||||
@ -160,30 +148,6 @@ export default {
|
|||||||
return tree;
|
return tree;
|
||||||
},
|
},
|
||||||
|
|
||||||
async checkAndCreateRepo(token) {
|
|
||||||
const url = `https://api.github.com/repos/${encodeURIComponent(token.name)}/${encodeURIComponent(appDataRepo)}`;
|
|
||||||
try {
|
|
||||||
await request(token, { url });
|
|
||||||
} catch (err) {
|
|
||||||
// create
|
|
||||||
if (err.status === 404) {
|
|
||||||
await request(token, {
|
|
||||||
method: 'POST',
|
|
||||||
url: 'https://api.github.com/repos/mafgwo/stackedit-appdata-template/generate',
|
|
||||||
body: {
|
|
||||||
owner: token.name,
|
|
||||||
name: appDataRepo,
|
|
||||||
description: 'StackEdit中文版默认空间.',
|
|
||||||
include_all_branches: false,
|
|
||||||
private: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://developer.github.com/v3/repos/commits/#list-commits-on-a-repository
|
* https://developer.github.com/v3/repos/commits/#list-commits-on-a-repository
|
||||||
*/
|
*/
|
||||||
@ -193,29 +157,11 @@ export default {
|
|||||||
repo,
|
repo,
|
||||||
sha,
|
sha,
|
||||||
path,
|
path,
|
||||||
tryTimes,
|
|
||||||
}) {
|
}) {
|
||||||
let tryCount = tryTimes || 1;
|
return repoRequest(token, owner, repo, {
|
||||||
try {
|
url: 'commits',
|
||||||
return repoRequest(token, owner, repo, {
|
params: { sha, path },
|
||||||
url: 'commits',
|
});
|
||||||
params: { sha, path },
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
// 主文档 并且 409 则重试3次
|
|
||||||
if (tryCount <= 3 && err.status === 409 && repo === appDataRepo) {
|
|
||||||
tryCount += 1;
|
|
||||||
return this.getCommits({
|
|
||||||
token,
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
sha,
|
|
||||||
path,
|
|
||||||
tryTimes: tryCount,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -233,12 +179,6 @@ export default {
|
|||||||
isImg,
|
isImg,
|
||||||
commitMessage,
|
commitMessage,
|
||||||
}) {
|
}) {
|
||||||
// 非法的文件名 不让提交
|
|
||||||
if (!path || path.endsWith('undefined')) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
resolve({ res: { content: { sha: null } } });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let uploadContent = content;
|
let uploadContent = content;
|
||||||
if (isImg && typeof content !== 'string') {
|
if (isImg && typeof content !== 'string') {
|
||||||
uploadContent = await utils.encodeFiletoBase64(content);
|
uploadContent = await utils.encodeFiletoBase64(content);
|
||||||
@ -288,30 +228,14 @@ export default {
|
|||||||
path,
|
path,
|
||||||
isImg,
|
isImg,
|
||||||
}) {
|
}) {
|
||||||
try {
|
const { sha, content } = await repoRequest(token, owner, repo, {
|
||||||
const { sha, content, encoding } = await repoRequest(token, owner, repo, {
|
url: `contents/${encodeURIComponent(path)}`,
|
||||||
url: `contents/${encodeURIComponent(path)}`,
|
params: { ref: branch },
|
||||||
params: { ref: branch },
|
});
|
||||||
});
|
return {
|
||||||
let tempContent = content;
|
sha,
|
||||||
// 如果是图片且 encoding 为 none 则 需要获取 blob
|
data: !isImg ? utils.decodeBase64(content) : content,
|
||||||
if (isImg && encoding === 'none') {
|
};
|
||||||
const blobInfo = await repoRequest(token, owner, repo, {
|
|
||||||
url: `git/blobs/${sha}`,
|
|
||||||
});
|
|
||||||
tempContent = blobInfo.content;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
sha,
|
|
||||||
data: !isImg ? utils.decodeBase64(tempContent) : tempContent,
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
// not .stackedit-data throw err
|
|
||||||
if (err.status === 404 && path.indexOf('.stackedit-data') >= 0) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 获取仓库信息
|
* 获取仓库信息
|
||||||
|
@ -3,9 +3,6 @@ import networkSvc from '../../networkSvc';
|
|||||||
import store from '../../../store';
|
import store from '../../../store';
|
||||||
import userSvc from '../../userSvc';
|
import userSvc from '../../userSvc';
|
||||||
import badgeSvc from '../../badgeSvc';
|
import badgeSvc from '../../badgeSvc';
|
||||||
import constants from '../../../data/constants';
|
|
||||||
|
|
||||||
const tokenExpirationMargin = 5 * 60 * 1000;
|
|
||||||
|
|
||||||
const request = ({ accessToken, serverUrl }, options) => networkSvc.request({
|
const request = ({ accessToken, serverUrl }, options) => networkSvc.request({
|
||||||
...options,
|
...options,
|
||||||
@ -53,90 +50,23 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* https://docs.gitlab.com/ee/api/oauth2.html
|
* https://docs.gitlab.com/ee/api/oauth2.html
|
||||||
*/
|
*/
|
||||||
async startOauth2(
|
async startOauth2(serverUrl, applicationId, sub = null, silent = false) {
|
||||||
serverUrl, applicationId, applicationSecret,
|
// Get an OAuth2 code
|
||||||
sub = null, silent = false, refreshToken,
|
const { accessToken } = await networkSvc.startOauth2(
|
||||||
) {
|
`${serverUrl}/oauth/authorize`,
|
||||||
let apiUrl = serverUrl;
|
{
|
||||||
let clientId = applicationId;
|
client_id: applicationId,
|
||||||
let useServerConf = false;
|
response_type: 'token',
|
||||||
// 获取gitlab配置的参数
|
scope: 'api',
|
||||||
await networkSvc.getServerConf();
|
},
|
||||||
const confClientId = store.getters['data/serverConf'].gitlabClientId;
|
silent,
|
||||||
const confServerUrl = store.getters['data/serverConf'].gitlabUrl;
|
);
|
||||||
// 存在gitlab配置则使用后端配置
|
|
||||||
if (confClientId && confServerUrl) {
|
|
||||||
apiUrl = confServerUrl;
|
|
||||||
clientId = confClientId;
|
|
||||||
useServerConf = true;
|
|
||||||
}
|
|
||||||
let tokenBody;
|
|
||||||
if (!silent) {
|
|
||||||
// Get an OAuth2 code
|
|
||||||
const { code } = await networkSvc.startOauth2(
|
|
||||||
`${apiUrl}/oauth/authorize`,
|
|
||||||
{
|
|
||||||
client_id: clientId,
|
|
||||||
response_type: 'code',
|
|
||||||
redirect_uri: constants.oauth2RedirectUri,
|
|
||||||
},
|
|
||||||
silent,
|
|
||||||
);
|
|
||||||
if (useServerConf) {
|
|
||||||
tokenBody = (await networkSvc.request({
|
|
||||||
method: 'GET',
|
|
||||||
url: 'oauth2/gitlabToken',
|
|
||||||
params: {
|
|
||||||
code,
|
|
||||||
grant_type: 'authorization_code',
|
|
||||||
redirect_uri: constants.oauth2RedirectUri,
|
|
||||||
},
|
|
||||||
})).body;
|
|
||||||
} else {
|
|
||||||
// Exchange code with token
|
|
||||||
tokenBody = (await networkSvc.request({
|
|
||||||
method: 'POST',
|
|
||||||
url: `${apiUrl}/oauth/token`,
|
|
||||||
params: {
|
|
||||||
client_id: clientId,
|
|
||||||
client_secret: applicationSecret,
|
|
||||||
code,
|
|
||||||
grant_type: 'authorization_code',
|
|
||||||
redirect_uri: constants.oauth2RedirectUri,
|
|
||||||
},
|
|
||||||
})).body;
|
|
||||||
}
|
|
||||||
} else if (useServerConf) {
|
|
||||||
tokenBody = (await networkSvc.request({
|
|
||||||
method: 'GET',
|
|
||||||
url: 'oauth2/gitlabToken',
|
|
||||||
params: {
|
|
||||||
refresh_token: refreshToken,
|
|
||||||
grant_type: 'refresh_token',
|
|
||||||
redirect_uri: constants.oauth2RedirectUri,
|
|
||||||
},
|
|
||||||
})).body;
|
|
||||||
} else {
|
|
||||||
// Exchange refreshToken with token
|
|
||||||
tokenBody = (await networkSvc.request({
|
|
||||||
method: 'POST',
|
|
||||||
url: `${apiUrl}/oauth/token`,
|
|
||||||
body: {
|
|
||||||
client_id: clientId,
|
|
||||||
client_secret: applicationSecret,
|
|
||||||
refresh_token: refreshToken,
|
|
||||||
grant_type: 'refresh_token',
|
|
||||||
redirect_uri: constants.oauth2RedirectUri,
|
|
||||||
},
|
|
||||||
})).body;
|
|
||||||
}
|
|
||||||
|
|
||||||
const accessToken = tokenBody.access_token;
|
|
||||||
// Call the user info endpoint
|
// Call the user info endpoint
|
||||||
const user = await request({ accessToken, serverUrl: apiUrl }, {
|
const user = await request({ accessToken, serverUrl }, {
|
||||||
url: 'user',
|
url: 'user',
|
||||||
});
|
});
|
||||||
const uniqueSub = `${apiUrl}/${user.id}`;
|
const uniqueSub = `${serverUrl}/${user.id}`;
|
||||||
userSvc.addUserInfo({
|
userSvc.addUserInfo({
|
||||||
id: `${subPrefix}:${uniqueSub}`,
|
id: `${subPrefix}:${uniqueSub}`,
|
||||||
name: user.username,
|
name: user.username,
|
||||||
@ -148,17 +78,11 @@ export default {
|
|||||||
throw new Error('GitLab account ID not expected.');
|
throw new Error('GitLab account ID not expected.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const oldToken = store.getters['data/gitlabTokensBySub'][uniqueSub];
|
|
||||||
// Build token object including scopes and sub
|
// Build token object including scopes and sub
|
||||||
const token = {
|
const token = {
|
||||||
accessToken,
|
accessToken,
|
||||||
name: user.username,
|
name: user.username,
|
||||||
applicationId: clientId,
|
serverUrl,
|
||||||
applicationSecret,
|
|
||||||
imgStorages: oldToken && oldToken.imgStorages,
|
|
||||||
refreshToken: tokenBody.refresh_token,
|
|
||||||
expiresOn: Date.now() + ((tokenBody.expires_in || 7200) * 1000),
|
|
||||||
serverUrl: apiUrl,
|
|
||||||
sub: uniqueSub,
|
sub: uniqueSub,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -166,58 +90,12 @@ export default {
|
|||||||
store.dispatch('data/addGitlabToken', token);
|
store.dispatch('data/addGitlabToken', token);
|
||||||
return token;
|
return token;
|
||||||
},
|
},
|
||||||
async addAccount(serverUrl, applicationId, applicationSecret, sub = null) {
|
async addAccount(serverUrl, applicationId, sub = null) {
|
||||||
const token = await this.startOauth2(serverUrl, applicationId, applicationSecret, sub);
|
const token = await this.startOauth2(serverUrl, applicationId, sub);
|
||||||
badgeSvc.addBadge('addGitLabAccount');
|
badgeSvc.addBadge('addGitLabAccount');
|
||||||
return token;
|
return token;
|
||||||
},
|
},
|
||||||
// 刷新token
|
|
||||||
async refreshToken(token) {
|
|
||||||
const {
|
|
||||||
serverUrl,
|
|
||||||
applicationId,
|
|
||||||
applicationSecret,
|
|
||||||
sub,
|
|
||||||
} = token;
|
|
||||||
const lastToken = store.getters['data/gitlabTokensBySub'][sub];
|
|
||||||
// 兼容旧的没有过期时间
|
|
||||||
if (!lastToken.expiresOn || !lastToken.refreshToken) {
|
|
||||||
await store.dispatch('modal/open', {
|
|
||||||
type: 'providerRedirection',
|
|
||||||
name: 'Gitlab',
|
|
||||||
});
|
|
||||||
return this.startOauth2(serverUrl, applicationId, applicationSecret, sub);
|
|
||||||
}
|
|
||||||
// lastToken is not expired
|
|
||||||
if (lastToken.expiresOn > Date.now() + tokenExpirationMargin) {
|
|
||||||
return lastToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
// existing token is about to expire.
|
|
||||||
// Try to get a new token in background
|
|
||||||
try {
|
|
||||||
return await this.startOauth2(
|
|
||||||
serverUrl, applicationId, applicationSecret,
|
|
||||||
sub, true, lastToken.refreshToken,
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
// If it fails try to popup a window
|
|
||||||
if (store.state.offline) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
await store.dispatch('modal/open', {
|
|
||||||
type: 'providerRedirection',
|
|
||||||
name: 'Gitlab',
|
|
||||||
});
|
|
||||||
return this.startOauth2(serverUrl, applicationId, applicationSecret, sub);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 带刷新token
|
|
||||||
async requestWithRefreshToken(token, options) {
|
|
||||||
const refreshedToken = await this.refreshToken(token);
|
|
||||||
const result = await request(refreshedToken, options);
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
* https://docs.gitlab.com/ee/api/projects.html#get-single-project
|
* https://docs.gitlab.com/ee/api/projects.html#get-single-project
|
||||||
*/
|
*/
|
||||||
@ -225,7 +103,8 @@ export default {
|
|||||||
if (projectId) {
|
if (projectId) {
|
||||||
return projectId;
|
return projectId;
|
||||||
}
|
}
|
||||||
const project = await this.requestWithRefreshToken(token, {
|
|
||||||
|
const project = await request(token, {
|
||||||
url: `projects/${encodeURIComponent(projectPath)}`,
|
url: `projects/${encodeURIComponent(projectPath)}`,
|
||||||
});
|
});
|
||||||
return project.id;
|
return project.id;
|
||||||
@ -239,7 +118,7 @@ export default {
|
|||||||
projectId,
|
projectId,
|
||||||
branch,
|
branch,
|
||||||
}) {
|
}) {
|
||||||
return this.requestWithRefreshToken(token, {
|
return request(token, {
|
||||||
url: `projects/${encodeURIComponent(projectId)}/repository/tree`,
|
url: `projects/${encodeURIComponent(projectId)}/repository/tree`,
|
||||||
params: {
|
params: {
|
||||||
ref: branch,
|
ref: branch,
|
||||||
@ -258,7 +137,7 @@ export default {
|
|||||||
branch,
|
branch,
|
||||||
path,
|
path,
|
||||||
}) {
|
}) {
|
||||||
return this.requestWithRefreshToken(token, {
|
return request(token, {
|
||||||
url: `projects/${encodeURIComponent(projectId)}/repository/commits`,
|
url: `projects/${encodeURIComponent(projectId)}/repository/commits`,
|
||||||
params: {
|
params: {
|
||||||
ref_name: branch,
|
ref_name: branch,
|
||||||
@ -278,26 +157,14 @@ export default {
|
|||||||
path,
|
path,
|
||||||
content,
|
content,
|
||||||
sha,
|
sha,
|
||||||
isImg,
|
|
||||||
commitMessage,
|
commitMessage,
|
||||||
}) {
|
}) {
|
||||||
// 非法的文件名 不让提交
|
return request(token, {
|
||||||
if (!path || path.endsWith('undefined')) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
resolve({ res: { content: { sha: null } } });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let uploadContent = content;
|
|
||||||
if (isImg && typeof content !== 'string') {
|
|
||||||
uploadContent = await utils.encodeFiletoBase64(content);
|
|
||||||
}
|
|
||||||
return this.requestWithRefreshToken(token, {
|
|
||||||
method: sha ? 'PUT' : 'POST',
|
method: sha ? 'PUT' : 'POST',
|
||||||
url: `projects/${encodeURIComponent(projectId)}/repository/files/${encodeURIComponent(path)}`,
|
url: `projects/${encodeURIComponent(projectId)}/repository/files/${encodeURIComponent(path)}`,
|
||||||
body: {
|
body: {
|
||||||
commit_message: commitMessage || getCommitMessage(sha ? 'updateFileMessage' : 'createFileMessage', path),
|
commit_message: commitMessage || getCommitMessage(sha ? 'updateFileMessage' : 'createFileMessage', path),
|
||||||
encoding: 'base64',
|
content,
|
||||||
content: isImg ? uploadContent : utils.encodeBase64(content),
|
|
||||||
last_commit_id: sha,
|
last_commit_id: sha,
|
||||||
branch,
|
branch,
|
||||||
},
|
},
|
||||||
@ -314,7 +181,7 @@ export default {
|
|||||||
path,
|
path,
|
||||||
sha,
|
sha,
|
||||||
}) {
|
}) {
|
||||||
return this.requestWithRefreshToken(token, {
|
return request(token, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
url: `projects/${encodeURIComponent(projectId)}/repository/files/${encodeURIComponent(path)}`,
|
url: `projects/${encodeURIComponent(projectId)}/repository/files/${encodeURIComponent(path)}`,
|
||||||
body: {
|
body: {
|
||||||
@ -333,15 +200,14 @@ export default {
|
|||||||
projectId,
|
projectId,
|
||||||
branch,
|
branch,
|
||||||
path,
|
path,
|
||||||
isImg,
|
|
||||||
}) {
|
}) {
|
||||||
const res = await this.requestWithRefreshToken(token, {
|
const res = await request(token, {
|
||||||
url: `projects/${encodeURIComponent(projectId)}/repository/files/${encodeURIComponent(path)}`,
|
url: `projects/${encodeURIComponent(projectId)}/repository/files/${encodeURIComponent(path)}`,
|
||||||
params: { ref: branch },
|
params: { ref: branch },
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
sha: res.last_commit_id,
|
sha: res.last_commit_id,
|
||||||
data: !isImg ? utils.decodeBase64(res.content) : res.content,
|
data: utils.decodeBase64(res.content),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -10,7 +10,8 @@ const tokenExpirationMargin = 5 * 60 * 1000; // 5 min (tokens expire after 1h)
|
|||||||
const driveAppDataScopes = ['https://www.googleapis.com/auth/drive.appdata'];
|
const driveAppDataScopes = ['https://www.googleapis.com/auth/drive.appdata'];
|
||||||
const getDriveScopes = token => [token.driveFullAccess
|
const getDriveScopes = token => [token.driveFullAccess
|
||||||
? 'https://www.googleapis.com/auth/drive'
|
? 'https://www.googleapis.com/auth/drive'
|
||||||
: 'https://www.googleapis.com/auth/drive.file'];
|
: 'https://www.googleapis.com/auth/drive.file',
|
||||||
|
'https://www.googleapis.com/auth/drive.install'];
|
||||||
const bloggerScopes = ['https://www.googleapis.com/auth/blogger'];
|
const bloggerScopes = ['https://www.googleapis.com/auth/blogger'];
|
||||||
const photosScopes = ['https://www.googleapis.com/auth/photos'];
|
const photosScopes = ['https://www.googleapis.com/auth/photos'];
|
||||||
|
|
||||||
|
@ -139,12 +139,6 @@ const requestPublish = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const publishLocationAndStore = async (publishLocation, commitMsg) => {
|
|
||||||
const publishLocationToStore = await publish(publishLocation, commitMsg);
|
|
||||||
workspaceSvc.addPublishLocation(publishLocationToStore);
|
|
||||||
return publishLocationToStore;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createPublishLocation = (publishLocation, featureId) => {
|
const createPublishLocation = (publishLocation, featureId) => {
|
||||||
const currentFile = store.getters['file/current'];
|
const currentFile = store.getters['file/current'];
|
||||||
publishLocation.fileId = currentFile.id;
|
publishLocation.fileId = currentFile.id;
|
||||||
@ -163,7 +157,8 @@ const createPublishLocation = (publishLocation, featureId) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await publishLocationAndStore(publishLocation, commitMsg);
|
const publishLocationToStore = await publish(publishLocation, commitMsg);
|
||||||
|
workspaceSvc.addPublishLocation(publishLocationToStore);
|
||||||
store.dispatch('notification/info', `添加了一个新的发布位置 "${currentFile.name}".`);
|
store.dispatch('notification/info', `添加了一个新的发布位置 "${currentFile.name}".`);
|
||||||
if (featureId) {
|
if (featureId) {
|
||||||
badgeSvc.addBadge(featureId);
|
badgeSvc.addBadge(featureId);
|
||||||
@ -174,6 +169,5 @@ const createPublishLocation = (publishLocation, featureId) => {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
requestPublish,
|
requestPublish,
|
||||||
publishLocationAndStore,
|
|
||||||
createPublishLocation,
|
createPublishLocation,
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,6 @@ import diffUtils from './diffUtils';
|
|||||||
import networkSvc from './networkSvc';
|
import networkSvc from './networkSvc';
|
||||||
import providerRegistry from './providers/common/providerRegistry';
|
import providerRegistry from './providers/common/providerRegistry';
|
||||||
import giteeAppDataProvider from './providers/giteeAppDataProvider';
|
import giteeAppDataProvider from './providers/giteeAppDataProvider';
|
||||||
import githubAppDataProvider from './providers/githubAppDataProvider';
|
|
||||||
import './providers/couchdbWorkspaceProvider';
|
import './providers/couchdbWorkspaceProvider';
|
||||||
import './providers/githubWorkspaceProvider';
|
import './providers/githubWorkspaceProvider';
|
||||||
import './providers/giteeWorkspaceProvider';
|
import './providers/giteeWorkspaceProvider';
|
||||||
@ -831,7 +830,7 @@ const syncWorkspace = async (skipContents = false) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (workspace.id === 'main') {
|
if (workspace.id === 'main') {
|
||||||
badgeSvc.addBadge(workspace.providerId === 'giteeAppData' ? 'syncMainWorkspace' : 'githubSyncMainWorkspace');
|
badgeSvc.addBadge('syncMainWorkspace');
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err && err.message === 'TOO_LATE') {
|
if (err && err.message === 'TOO_LATE') {
|
||||||
@ -970,15 +969,6 @@ const requestSync = (addTriggerSyncBadge = false) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const afterSignIn = async () => {
|
|
||||||
if (store.getters['workspace/currentWorkspace'].id === 'main' && workspaceProvider) {
|
|
||||||
const mainToken = store.getters['workspace/mainWorkspaceToken'];
|
|
||||||
// Try to find a suitable workspace sync provider
|
|
||||||
workspaceProvider = mainToken.providerId === 'githubAppData' ? githubAppDataProvider : giteeAppDataProvider;
|
|
||||||
await workspaceProvider.initWorkspace();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async init() {
|
async init() {
|
||||||
// Load workspaces and tokens from localStorage
|
// Load workspaces and tokens from localStorage
|
||||||
@ -990,11 +980,10 @@ export default {
|
|||||||
await actionProvider.initAction();
|
await actionProvider.initAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
const mainToken = store.getters['workspace/mainWorkspaceToken'];
|
|
||||||
// Try to find a suitable workspace sync provider
|
// Try to find a suitable workspace sync provider
|
||||||
workspaceProvider = providerRegistry.providersById[utils.queryParams.providerId];
|
workspaceProvider = providerRegistry.providersById[utils.queryParams.providerId];
|
||||||
if (!workspaceProvider || !workspaceProvider.initWorkspace) {
|
if (!workspaceProvider || !workspaceProvider.initWorkspace) {
|
||||||
workspaceProvider = mainToken && mainToken.providerId === 'githubAppData' ? githubAppDataProvider : giteeAppDataProvider;
|
workspaceProvider = giteeAppDataProvider;
|
||||||
}
|
}
|
||||||
const workspace = await workspaceProvider.initWorkspace();
|
const workspace = await workspaceProvider.initWorkspace();
|
||||||
// Fix the URL hash
|
// Fix the URL hash
|
||||||
@ -1052,7 +1041,6 @@ export default {
|
|||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
afterSignIn,
|
|
||||||
syncImg,
|
syncImg,
|
||||||
isSyncPossible,
|
isSyncPossible,
|
||||||
requestSync,
|
requestSync,
|
||||||
|
@ -317,7 +317,7 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
parseGitlabProjectPath(url) {
|
parseGitlabProjectPath(url) {
|
||||||
const parsedProject = url && url.match(/^http[s]?:\/\/[^/]+\/(.+?)(?:\.git|\/)?$/);
|
const parsedProject = url && url.match(/^https:\/\/[^/]+\/(.+?)(?:\.git|\/)?$/);
|
||||||
return parsedProject && parsedProject[1];
|
return parsedProject && parsedProject[1];
|
||||||
},
|
},
|
||||||
parseGiteaProjectPath(url) {
|
parseGiteaProjectPath(url) {
|
||||||
@ -400,8 +400,7 @@ export default {
|
|||||||
return path || '';
|
return path || '';
|
||||||
},
|
},
|
||||||
// 根据当前绝对路径 与 文件路径计算出文件绝对路径
|
// 根据当前绝对路径 与 文件路径计算出文件绝对路径
|
||||||
getAbsoluteFilePath(currDirNode, originFilePath) {
|
getAbsoluteFilePath(currDirNode, filePath) {
|
||||||
const filePath = originFilePath && originFilePath.replaceAll('\\', '/');
|
|
||||||
const currAbsolutePath = this.getAbsoluteDir(currDirNode);
|
const currAbsolutePath = this.getAbsoluteDir(currDirNode);
|
||||||
// "/"开头说明已经是绝对路径
|
// "/"开头说明已经是绝对路径
|
||||||
if (filePath.indexOf('/') === 0) {
|
if (filePath.indexOf('/') === 0) {
|
||||||
|
@ -8,8 +8,6 @@ import defaultLayoutSettings from '../data/defaults/defaultLayoutSettings';
|
|||||||
import plainHtmlTemplate from '../data/templates/plainHtmlTemplate.html';
|
import plainHtmlTemplate from '../data/templates/plainHtmlTemplate.html';
|
||||||
import styledHtmlTemplate from '../data/templates/styledHtmlTemplate.html';
|
import styledHtmlTemplate from '../data/templates/styledHtmlTemplate.html';
|
||||||
import styledHtmlWithTocTemplate from '../data/templates/styledHtmlWithTocTemplate.html';
|
import styledHtmlWithTocTemplate from '../data/templates/styledHtmlWithTocTemplate.html';
|
||||||
import styledHtmlWithThemeTemplate from '../data/templates/styledHtmlWithThemeTemplate.html';
|
|
||||||
import styledHtmlWithThemeAndTocTemplate from '../data/templates/styledHtmlWithThemeAndTocTemplate.html';
|
|
||||||
import jekyllSiteTemplate from '../data/templates/jekyllSiteTemplate.html';
|
import jekyllSiteTemplate from '../data/templates/jekyllSiteTemplate.html';
|
||||||
import constants from '../data/constants';
|
import constants from '../data/constants';
|
||||||
import features from '../data/features';
|
import features from '../data/features';
|
||||||
@ -95,12 +93,10 @@ const makeAdditionalTemplate = (name, value, helpers = '\n') => ({
|
|||||||
isAdditional: true,
|
isAdditional: true,
|
||||||
});
|
});
|
||||||
const defaultTemplates = {
|
const defaultTemplates = {
|
||||||
plainText: makeAdditionalTemplate('Markdown文本', '{{{files.0.content.text}}}'),
|
plainText: makeAdditionalTemplate('Plain text', '{{{files.0.content.text}}}'),
|
||||||
plainHtml: makeAdditionalTemplate('无样式HTML', plainHtmlTemplate),
|
plainHtml: makeAdditionalTemplate('Plain HTML', plainHtmlTemplate),
|
||||||
styledHtml: makeAdditionalTemplate('标准样式HTML', styledHtmlTemplate),
|
styledHtml: makeAdditionalTemplate('Styled HTML', styledHtmlTemplate),
|
||||||
styledHtmlWithToc: makeAdditionalTemplate('带目录标准样式HTML', styledHtmlWithTocTemplate),
|
styledHtmlWithToc: makeAdditionalTemplate('Styled HTML with TOC', styledHtmlWithTocTemplate),
|
||||||
styledHtmlWithTheme: makeAdditionalTemplate('带预览主题HTML', styledHtmlWithThemeTemplate),
|
|
||||||
styledHtmlWithThemeAndToc: makeAdditionalTemplate('带目录预览主题HTML', styledHtmlWithThemeAndTocTemplate),
|
|
||||||
jekyllSite: makeAdditionalTemplate('Jekyll site', jekyllSiteTemplate),
|
jekyllSite: makeAdditionalTemplate('Jekyll site', jekyllSiteTemplate),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import utils from '../services/utils';
|
import utils from '../services/utils';
|
||||||
import giteeHelper from '../services/providers/helpers/giteeHelper';
|
import giteeHelper from '../services/providers/helpers/giteeHelper';
|
||||||
import githubHelper from '../services/providers/helpers/githubHelper';
|
|
||||||
import syncSvc from '../services/syncSvc';
|
import syncSvc from '../services/syncSvc';
|
||||||
|
|
||||||
const idShifter = offset => (state, getters) => {
|
const idShifter = offset => (state, getters) => {
|
||||||
@ -137,13 +136,8 @@ export default {
|
|||||||
const loginToken = rootGetters['workspace/loginToken'];
|
const loginToken = rootGetters['workspace/loginToken'];
|
||||||
if (!loginToken) {
|
if (!loginToken) {
|
||||||
try {
|
try {
|
||||||
const signInWhere = await dispatch('modal/open', 'signInForComment', { root: true });
|
await dispatch('modal/open', 'signInForComment', { root: true });
|
||||||
if (signInWhere === 'github') {
|
await giteeHelper.signin();
|
||||||
await githubHelper.signin();
|
|
||||||
} else {
|
|
||||||
await giteeHelper.signin();
|
|
||||||
}
|
|
||||||
await syncSvc.afterSignIn();
|
|
||||||
syncSvc.requestSync();
|
syncSvc.requestSync();
|
||||||
await dispatch('createNewDiscussion', selection);
|
await dispatch('createNewDiscussion', selection);
|
||||||
} catch (e) { /* cancel */ }
|
} catch (e) { /* cancel */ }
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
const localKey = 'theme/currEditTheme';
|
const localKey = 'theme/currEditTheme';
|
||||||
const customEditThemeKey = 'theme/customEditThemeStyle';
|
const customEditThemeKey = 'theme/customEditThemeStyle';
|
||||||
const previewLocalKey = 'theme/currPreviewTheme';
|
|
||||||
const customPreviewThemeKey = 'theme/customPreviewThemeStyle';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
@ -9,9 +7,6 @@ export default {
|
|||||||
// 当前编辑主题
|
// 当前编辑主题
|
||||||
currEditTheme: '',
|
currEditTheme: '',
|
||||||
customEditThemeStyle: null,
|
customEditThemeStyle: null,
|
||||||
// 当前预览主题
|
|
||||||
currPreviewTheme: '',
|
|
||||||
customPreviewThemeStyle: null,
|
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
setEditTheme: (state, value) => {
|
setEditTheme: (state, value) => {
|
||||||
@ -20,18 +15,10 @@ export default {
|
|||||||
setCustomEditThemeStyle: (state, value) => {
|
setCustomEditThemeStyle: (state, value) => {
|
||||||
state.customEditThemeStyle = value;
|
state.customEditThemeStyle = value;
|
||||||
},
|
},
|
||||||
setPreviewTheme: (state, value) => {
|
|
||||||
state.currPreviewTheme = value;
|
|
||||||
},
|
|
||||||
setCustomPreviewThemeStyle: (state, value) => {
|
|
||||||
state.customPreviewThemeStyle = value;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
currEditTheme: state => state.currEditTheme,
|
currEditTheme: state => state.currEditTheme,
|
||||||
customEditThemeStyle: state => state.customEditThemeStyle,
|
customEditThemeStyle: state => state.customEditThemeStyle,
|
||||||
currPreviewTheme: state => state.currPreviewTheme,
|
|
||||||
customPreviewThemeStyle: state => state.customPreviewThemeStyle,
|
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async setEditTheme({ commit }, theme) {
|
async setEditTheme({ commit }, theme) {
|
||||||
@ -84,55 +71,5 @@ export default {
|
|||||||
commit('setCustomEditThemeStyle', value);
|
commit('setCustomEditThemeStyle', value);
|
||||||
localStorage.setItem(customEditThemeKey, value);
|
localStorage.setItem(customEditThemeKey, value);
|
||||||
},
|
},
|
||||||
async setPreviewTheme({ commit }, theme) {
|
|
||||||
// 如果不是default 则加载样式
|
|
||||||
if (!theme || theme === 'default') {
|
|
||||||
commit('setPreviewTheme', theme);
|
|
||||||
localStorage.setItem(previewLocalKey, theme);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const themeStyle = document.getElementById(`preview-theme-${theme}`);
|
|
||||||
if (themeStyle) {
|
|
||||||
commit('setPreviewTheme', theme);
|
|
||||||
localStorage.setItem(previewLocalKey, theme);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 如果是自定义则直接追加
|
|
||||||
if (theme === 'custom') {
|
|
||||||
const styleEle = document.createElement('style');
|
|
||||||
styleEle.id = `preview-theme-${theme}`;
|
|
||||||
styleEle.type = 'text/css';
|
|
||||||
styleEle.innerHTML = localStorage.getItem(customPreviewThemeKey) || '';
|
|
||||||
commit('setCustomPreviewThemeStyle', styleEle.innerHTML);
|
|
||||||
document.head.appendChild(styleEle);
|
|
||||||
commit('setPreviewTheme', theme);
|
|
||||||
localStorage.setItem(previewLocalKey, theme);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const script = document.createElement('script');
|
|
||||||
let timeout;
|
|
||||||
try {
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
script.onload = resolve;
|
|
||||||
script.onerror = reject;
|
|
||||||
script.src = `/themes/preview-theme-${theme}.js`;
|
|
||||||
try {
|
|
||||||
document.head.appendChild(script);
|
|
||||||
timeout = setTimeout(reject, 30);
|
|
||||||
commit('setPreviewTheme', theme);
|
|
||||||
localStorage.setItem(previewLocalKey, theme);
|
|
||||||
} catch (e) {
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
document.head.removeChild(script);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setCustomPreviewThemeStyle({ commit }, value) {
|
|
||||||
commit('setCustomPreviewThemeStyle', value);
|
|
||||||
localStorage.setItem(customPreviewThemeKey, value);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -22,7 +22,7 @@ export default {
|
|||||||
Object.entries(rootGetters['data/workspaces']).forEach(([id, workspace]) => {
|
Object.entries(rootGetters['data/workspaces']).forEach(([id, workspace]) => {
|
||||||
const sanitizedWorkspace = {
|
const sanitizedWorkspace = {
|
||||||
id,
|
id,
|
||||||
providerId: (mainWorkspaceToken && mainWorkspaceToken.providerId) || 'giteeAppData',
|
providerId: 'giteeAppData',
|
||||||
sub: mainWorkspaceToken && mainWorkspaceToken.sub,
|
sub: mainWorkspaceToken && mainWorkspaceToken.sub,
|
||||||
...workspace,
|
...workspace,
|
||||||
};
|
};
|
||||||
@ -47,19 +47,17 @@ export default {
|
|||||||
|| currentWorkspace.providerId === 'giteeWorkspace'
|
|| currentWorkspace.providerId === 'giteeWorkspace'
|
||||||
|| currentWorkspace.providerId === 'gitlabWorkspace'
|
|| currentWorkspace.providerId === 'gitlabWorkspace'
|
||||||
|| currentWorkspace.providerId === 'giteaWorkspace'
|
|| currentWorkspace.providerId === 'giteaWorkspace'
|
||||||
|| currentWorkspace.providerId === 'giteeAppData'
|
|| currentWorkspace.providerId === 'giteeAppData',
|
||||||
|| currentWorkspace.providerId === 'githubAppData',
|
|
||||||
currentWorkspaceHasUniquePaths: (state, { currentWorkspace }) =>
|
currentWorkspaceHasUniquePaths: (state, { currentWorkspace }) =>
|
||||||
currentWorkspace.providerId === 'githubWorkspace'
|
currentWorkspace.providerId === 'githubWorkspace'
|
||||||
|| currentWorkspace.providerId === 'giteeWorkspace'
|
|| currentWorkspace.providerId === 'giteeWorkspace'
|
||||||
|| currentWorkspace.providerId === 'gitlabWorkspace'
|
|| currentWorkspace.providerId === 'gitlabWorkspace'
|
||||||
|| currentWorkspace.providerId === 'giteaWorkspace'
|
|| currentWorkspace.providerId === 'giteaWorkspace'
|
||||||
|| currentWorkspace.providerId === 'giteeAppData'
|
|| currentWorkspace.providerId === 'giteeAppData',
|
||||||
|| currentWorkspace.providerId === 'githubAppData',
|
|
||||||
lastSyncActivityKey: (state, { currentWorkspace }) => `${currentWorkspace.id}/lastSyncActivity`,
|
lastSyncActivityKey: (state, { currentWorkspace }) => `${currentWorkspace.id}/lastSyncActivity`,
|
||||||
lastFocusKey: (state, { currentWorkspace }) => `${currentWorkspace.id}/lastWindowFocus`,
|
lastFocusKey: (state, { currentWorkspace }) => `${currentWorkspace.id}/lastWindowFocus`,
|
||||||
mainWorkspaceToken: (state, getters, rootState, rootGetters) =>
|
mainWorkspaceToken: (state, getters, rootState, rootGetters) =>
|
||||||
utils.someResult([...Object.values(rootGetters['data/giteeTokensBySub']), ...Object.values(rootGetters['data/githubTokensBySub'])], (token) => {
|
utils.someResult(Object.values(rootGetters['data/giteeTokensBySub']), (token) => {
|
||||||
if (token.isLogin) {
|
if (token.isLogin) {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@ -87,10 +85,8 @@ export default {
|
|||||||
switch (currentWorkspace.providerId) {
|
switch (currentWorkspace.providerId) {
|
||||||
case 'googleDriveWorkspace':
|
case 'googleDriveWorkspace':
|
||||||
return 'google';
|
return 'google';
|
||||||
case 'githubAppData':
|
|
||||||
case 'githubWorkspace':
|
case 'githubWorkspace':
|
||||||
return 'github';
|
return 'github';
|
||||||
case 'giteeAppData':
|
|
||||||
case 'giteeWorkspace':
|
case 'giteeWorkspace':
|
||||||
default:
|
default:
|
||||||
return 'gitee';
|
return 'gitee';
|
||||||
|
@ -99,7 +99,7 @@ samp {
|
|||||||
blockquote {
|
blockquote {
|
||||||
color: rgba(0, 0, 0, 0.5);
|
color: rgba(0, 0, 0, 0.5);
|
||||||
padding: 0.5em 1em;
|
padding: 0.5em 1em;
|
||||||
border-left: 8px solid #cfd1d6;
|
border-left: 8px solid rgba(0, 0, 0, 0.1);
|
||||||
background: #e2e4e9;
|
background: #e2e4e9;
|
||||||
word-break: break-word !important;
|
word-break: break-word !important;
|
||||||
|
|
||||||
@ -302,6 +302,11 @@ img {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.stackedit--pdf {
|
.stackedit--pdf {
|
||||||
|
blockquote {
|
||||||
|
// wkhtmltopdf doesn't like borders with transparency
|
||||||
|
border-left-color: #ececec;
|
||||||
|
}
|
||||||
|
|
||||||
.stackedit__html {
|
.stackedit__html {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
|
Before Width: | Height: | Size: 264 KiB After Width: | Height: | Size: 17 KiB |
@ -1,169 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title>文章分享 - Markdown编辑器</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="canonical" href="https://md.jonylee.top/">
|
|
||||||
<link rel="icon" href="static/landing/favicon.ico" type="image/x-icon">
|
|
||||||
<link rel="shortcut icon" href="static/landing/favicon.ico" type="image/x-icon">
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="keywords" content="Markdown编辑器,StackEdit中文版,StackEdit汉化版,StackEdit,在线Markdown,笔记利器,Markdown笔记">
|
|
||||||
<meta name="description" content="支持直接将码云(Gitee)、GitHub、Gitea等仓库作为笔记存储仓库且支持拖拽/粘贴上传图片,并且可以直接在页面编辑同步和管理的Markdown编辑器。">
|
|
||||||
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
|
||||||
<meta name="baidu-site-verification" content="code-tGpn2BT069" />
|
|
||||||
<meta name="msvalidate.01" content="90A9558158543277BD284CFA054E7F5B" />
|
|
||||||
<link rel="stylesheet" href="style.css">
|
|
||||||
<style>
|
|
||||||
.share-header {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
background-color: #383c4a;
|
|
||||||
color: #fff;
|
|
||||||
padding: 10px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
z-index: 99999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-header .logo {
|
|
||||||
margin: 0 0 -8px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-header nav {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-header nav ul {
|
|
||||||
list-style-type: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-header nav li {
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-header nav a {
|
|
||||||
color: #fff;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-header nav a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-content {
|
|
||||||
transform: translateY(50px);
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script type="text/javascript">
|
|
||||||
function getQueryString(name) {
|
|
||||||
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
|
|
||||||
var r = window.location.search.substr(1).match(reg);
|
|
||||||
if (r != null) {
|
|
||||||
return unescape(r[2]);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendTagHtml(newdoc, tagName, targetParentEle) {
|
|
||||||
const tags = newdoc.getElementsByTagName(tagName);
|
|
||||||
if (!tags) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < tags.length; i++) {
|
|
||||||
targetParentEle.append(tags[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onload = function() {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
const gistId = getQueryString('id');
|
|
||||||
let accessToken = null;
|
|
||||||
const tokens = window.localStorage.getItem('data/tokens');
|
|
||||||
if (tokens) {
|
|
||||||
const tokensObj = JSON.parse(tokens);
|
|
||||||
if (tokensObj.data && tokensObj.data.github) {
|
|
||||||
const tokenArr = Object.keys(tokensObj.data.github).map(it => tokensObj.data.github[it]).filter(it => it && it.isLogin);
|
|
||||||
if (tokenArr.length > 0) {
|
|
||||||
accessToken = tokenArr[0].accessToken;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const url = `https://api.github.com/gists/${gistId}`;
|
|
||||||
xhr.open('GET', url);
|
|
||||||
if (accessToken) {
|
|
||||||
xhr.setRequestHeader('Authorization', `Bearer ${accessToken}`);
|
|
||||||
}
|
|
||||||
xhr.onload = function() {
|
|
||||||
if (xhr.status === 200) {
|
|
||||||
const newdoc = document.implementation.createHTMLDocument("");
|
|
||||||
const body = JSON.parse(xhr.responseText);
|
|
||||||
for (let key in body.files) {
|
|
||||||
newdoc.documentElement.innerHTML = body.files[key].content;
|
|
||||||
}
|
|
||||||
const currHead = document.head;
|
|
||||||
// head
|
|
||||||
appendTagHtml(newdoc, 'style', currHead);
|
|
||||||
// title
|
|
||||||
document.title = newdoc.title + ' - StackEdit中文版';
|
|
||||||
// 内容
|
|
||||||
const shareContent = document.getElementsByClassName('share-content')[0];
|
|
||||||
shareContent.innerHTML = newdoc.body.innerHTML;
|
|
||||||
document.body.className = newdoc.body.className;
|
|
||||||
} else if (xhr.status === 403) {
|
|
||||||
const rateLimit = xhr.responseText && xhr.responseText.indexOf('Rate Limit') >= 0;
|
|
||||||
const appUri = `${window.location.protocol}//${window.location.host}/app`;
|
|
||||||
document.getElementById('div_info').innerHTML = `${rateLimit ? "请求太过频繁" : "无权限访问"},请使用GitHub登录 <a href="${appUri}" target="_brank">主文档空间</a> 后再刷新此页面!`;
|
|
||||||
} else {
|
|
||||||
console.error('An error occurred: ' + xhr.status);
|
|
||||||
document.getElementById('div_info').innerHTML = `分享内容获取失败或已失效!请使用GitHub登录 <a href="${appUri}" target="_brank">主文档空间</a> 后再刷新此页面!`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="share-header">
|
|
||||||
<nav>
|
|
||||||
<a class="logo" href="https://md.jonylee.top" target="_blank">
|
|
||||||
<img src="static/landing/logo.svg" height="30px" />
|
|
||||||
</a>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://md.jonylee.top" target="_blank">首页</a></li>
|
|
||||||
<li><a href="https://md.jonylee.top/app" target="_blank">写笔记</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
<div class="share-content stackedit">
|
|
||||||
<div id="div_info" style="text-align: center; height: 600px;">文章加载中......</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
|
|
||||||
|
|
||||||
<!-- built files will be auto injected -->
|
|
||||||
<!-- baidu统计-->
|
|
||||||
<script>
|
|
||||||
var _hmt = _hmt || [];
|
|
||||||
(function() {
|
|
||||||
var hm = document.createElement("script");
|
|
||||||
hm.src = "https://hm.baidu.com/hm.js?dad4b4383b13eedea1ab45ee323df1c3";
|
|
||||||
var s = document.getElementsByTagName("script")[0];
|
|
||||||
s.parentNode.insertBefore(hm, s);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
<!-- baidu统计结束-->
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
@ -2,13 +2,14 @@
|
|||||||
<html manifest="cache.manifest">
|
<html manifest="cache.manifest">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Markdown编辑器-JonyLee的设计导航</title>
|
<title>StackEdit中文版 – 浏览器内 Markdown 编辑器</title>
|
||||||
<link rel="canonical" href="https://md.jonylee.top/">
|
<link rel="canonical" href="https://stackedit.cn/">
|
||||||
<link rel="icon" href="static/landing/favicon.ico" type="image/x-icon">
|
<link rel="icon" href="static/landing/favicon.ico" type="image/x-icon">
|
||||||
<link rel="shortcut icon" href="static/landing/favicon.ico" type="image/x-icon">
|
<link rel="shortcut icon" href="static/landing/favicon.ico" type="image/x-icon">
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="keywords" content="Markdown编辑器,StackEdit中文版,StackEdit汉化版,StackEdit,在线Markdown,笔记利器,Markdown笔记">
|
<meta name="keywords" content="Markdown编辑器,StackEdit中文版,StackEdit汉化版,StackEdit,在线Markdown,笔记利器,Markdown笔记">
|
||||||
<meta name="description" content="支持直接将码云(Gitee)、GitHub、Gitea等仓库作为笔记存储仓库且支持拖拽/粘贴上传图片,并且可以直接在页面编辑同步和管理的Markdown编辑器。">
|
<meta name="description"
|
||||||
|
content="支持直接将码云(Gitee)、GitHub、Gitea等仓库作为笔记存储仓库且支持拖拽/粘贴上传图片,并且可以直接在页面编辑同步和管理的Markdown编辑器。">
|
||||||
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
<meta name="baidu-site-verification" content="code-tGpn2BT069" />
|
<meta name="baidu-site-verification" content="code-tGpn2BT069" />
|
||||||
<meta name="msvalidate.01" content="90A9558158543277BD284CFA054E7F5B" />
|
<meta name="msvalidate.01" content="90A9558158543277BD284CFA054E7F5B" />
|
||||||
@ -231,6 +232,7 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.social .icon {
|
.social .icon {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
@ -259,9 +261,7 @@
|
|||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
function scrollTo(selector) {
|
function scrollTo(selector) {
|
||||||
$('html,body').animate({
|
$('html,body').animate({scrollTop: $(selector).offset().top}, 500);
|
||||||
scrollTop: $(selector).offset().top
|
|
||||||
}, 500);
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
@ -270,18 +270,34 @@
|
|||||||
<div class="landing">
|
<div class="landing">
|
||||||
<div class="navigation-bar">
|
<div class="navigation-bar">
|
||||||
<a class="navigation-bar__button button" href="app" title="The app">
|
<a class="navigation-bar__button button" href="app" title="The app">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="icon"><path d="M 16.8363,2.73375C 16.45,2.73375 16.0688,2.88125 15.7712,3.17375L 13.6525,5.2925L 18.955,10.5962L 21.0737,8.47625C 21.665,7.89 21.665,6.94375 21.0737,6.3575L 17.895,3.17375C 17.6025,2.88125 17.2163,2.73375 16.8363,2.73375 Z M 12.9437,6.00125L 4.84375,14.1062L 7.4025,14.39L 7.57875,16.675L 9.85875,16.85L 10.1462,19.4088L 18.2475,11.3038M 4.2475,15.0437L 2.515,21.7337L 9.19875,19.9412L 8.955,17.7838L 6.645,17.6075L 6.465,15.2925"></path></svg> 开始写作
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="icon"><path d="M 16.8363,2.73375C 16.45,2.73375 16.0688,2.88125 15.7712,3.17375L 13.6525,5.2925L 18.955,10.5962L 21.0737,8.47625C 21.665,7.89 21.665,6.94375 21.0737,6.3575L 17.895,3.17375C 17.6025,2.88125 17.2163,2.73375 16.8363,2.73375 Z M 12.9437,6.00125L 4.84375,14.1062L 7.4025,14.39L 7.57875,16.675L 9.85875,16.85L 10.1462,19.4088L 18.2475,11.3038M 4.2475,15.0437L 2.515,21.7337L 9.19875,19.9412L 8.955,17.7838L 6.645,17.6075L 6.465,15.2925"></path></svg>
|
||||||
|
开始写作
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="splash-screen">
|
<div class="splash-screen">
|
||||||
<div class="splash-screen__logo">
|
<div class="splash-screen__logo">
|
||||||
<div class="splash-screen__subtitle">
|
<div class="splash-screen__subtitle">
|
||||||
浏览器内 Markdown 笔记利器
|
笔记利器(浏览器内 Markdown 编辑器)
|
||||||
|
|
||||||
|
<div class="social">
|
||||||
|
<a href="https://jq.qq.com/?_wv=1027&k=wUSCNqmN" target="_blank" title="QQ交流群">
|
||||||
|
<svg t="1665396466500" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3543" width="32" height="32">
|
||||||
|
<path d="M512 0C229.12 0 0 229.12 0 512c0 282.88 229.12 512 512 512s512-229.12 512-512C1024 229.12 794.88 0 512 0zM782.08 670.72c-11.52 6.4-30.72-7.68-48.64-34.56-6.4 28.16-24.32 53.76-48.64 74.24 25.6 8.96 42.24 25.6 42.24 42.24 0 29.44-46.08 52.48-102.4 52.48-51.2 0-93.44-19.2-101.12-43.52-2.56 0-10.24 0-12.8 0-7.68 24.32-49.92 43.52-101.12 43.52-56.32 0-102.4-23.04-102.4-52.48 0-17.92 16.64-33.28 42.24-42.24-24.32-20.48-42.24-46.08-48.64-74.24-17.92 25.6-37.12 39.68-48.64 34.56-17.92-8.96-14.08-57.6 7.68-107.52 16.64-39.68 39.68-69.12 57.6-75.52 0-2.56 0-5.12 0-7.68 0-15.36 3.84-29.44 11.52-40.96 0-1.28 0-1.28 0-2.56 0-7.68 1.28-14.08 5.12-19.2C340.48 312.32 408.32 230.4 518.4 230.4c110.08 0 177.92 81.92 183.04 185.6 2.56 5.12 5.12 12.8 5.12 19.2 0 1.28 0 1.28 0 2.56 7.68 11.52 11.52 25.6 11.52 40.96 0 2.56 0 5.12 0 7.68 17.92 6.4 40.96 35.84 57.6 75.52C796.16 613.12 800 661.76 782.08 670.72z" p-id="3544"></path>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a href="https://gitee.com/mafgwo/stackedit" target="_blank" title="码云开源仓库">
|
||||||
|
<svg t="1652950823759" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2991" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<defs><style type="text/css"></style></defs>
|
||||||
|
<path d="M512 1024C229.222 1024 0 794.778 0 512S229.222 0 512 0s512 229.222 512 512-229.222 512-512 512z m259.149-568.883h-290.74a25.293 25.293 0 0 0-25.292 25.293l-0.026 63.206c0 13.952 11.315 25.293 25.267 25.293h177.024c13.978 0 25.293 11.315 25.293 25.267v12.646a75.853 75.853 0 0 1-75.853 75.853h-240.23a25.293 25.293 0 0 1-25.267-25.293V417.203a75.853 75.853 0 0 1 75.827-75.853h353.946a25.293 25.293 0 0 0 25.267-25.292l0.077-63.207a25.293 25.293 0 0 0-25.268-25.293H417.152a189.62 189.62 0 0 0-189.62 189.645V771.15c0 13.977 11.316 25.293 25.294 25.293h372.94a170.65 170.65 0 0 0 170.65-170.65V480.384a25.293 25.293 0 0 0-25.293-25.267z" fill="#C71D23" p-id="2992"></path>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="splash-screen__footer">
|
<div class="splash-screen__footer">
|
||||||
<a class="button" href="javascript:scrollTo($('.anchor'))">
|
<a class="button" href="javascript:scrollTo($('.anchor'))">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="icon"><path d="M 11,4L 13,4L 13,16.0104L 18.5052,10.5052L 19.9194,11.9194L 12,19.8388L 4.08058,11.9194L 5.49479,10.5052L 11,16.0104L 11,4 Z "/></path></svg> 阅读更多
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="icon"><path d="M 11,4L 13,4L 13,16.0104L 18.5052,10.5052L 19.9194,11.9194L 12,19.8388L 4.08058,11.9194L 5.49479,10.5052L 11,16.0104L 11,4 Z "/></path></svg>
|
||||||
|
阅读更多
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -416,24 +432,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="image" style="width: 250px">
|
<div class="image" style="width: 250px">
|
||||||
<img width="230" src="static/landing/twemoji.png">
|
<img width="230" src="static/landing/twemoji.png">
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
</div>
|
||||||
<div class="feature">
|
<div class="column">
|
||||||
<h3>Emojis表情</h3>
|
<div class="feature">
|
||||||
<p>StackEdit中文版 支持使用 Markdown 表情符号标记在文件中插入表情符号。</p>
|
<h3>Emojis表情</h3>
|
||||||
</div>
|
<p>StackEdit中文版 支持使用 Markdown 表情符号标记在文件中插入表情符号。</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="landing__footer">
|
<div class="landing__footer">
|
||||||
<a href="app" title="Markdown编辑器">Markdown编辑器</a> – <a href="https://gitee.com/mafgwo" target="_blank" title="豆萁">代码作者</a><br> Copyright ©
|
<div class="social">
|
||||||
<script>
|
<a href="https://gitee.com/mafgwo/stackedit" target="_blank">
|
||||||
document.write((new Date()).getFullYear())
|
<svg t="1652950823759" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2991" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
</script> <a href="https://jonylee.top">JonyLee</a> & <a href="https://beian.miit.gov.cn/" target="_blank">沪ICP备2023021298号-1</a><br> 开源许可
|
<defs><style type="text/css"></style></defs>
|
||||||
|
<path d="M512 1024C229.222 1024 0 794.778 0 512S229.222 0 512 0s512 229.222 512 512-229.222 512-512 512z m259.149-568.883h-290.74a25.293 25.293 0 0 0-25.292 25.293l-0.026 63.206c0 13.952 11.315 25.293 25.267 25.293h177.024c13.978 0 25.293 11.315 25.293 25.267v12.646a75.853 75.853 0 0 1-75.853 75.853h-240.23a25.293 25.293 0 0 1-25.267-25.293V417.203a75.853 75.853 0 0 1 75.827-75.853h353.946a25.293 25.293 0 0 0 25.267-25.292l0.077-63.207a25.293 25.293 0 0 0-25.268-25.293H417.152a189.62 189.62 0 0 0-189.62 189.645V771.15c0 13.977 11.316 25.293 25.294 25.293h372.94a170.65 170.65 0 0 0 170.65-170.65V480.384a25.293 25.293 0 0 0-25.293-25.267z" fill="#C71D23" p-id="2992"></path>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<a href="app" title="The app">The app</a> – <a href="https://gitee.com/mafgwo/stackedit/issues" target="_blank" title="The app">Community</a><br>
|
||||||
|
© 2022 <a href="https://gitee.com/mafgwo" target="_blank">豆萁</a> <a href="https://beian.miit.gov.cn/" target="_blank">粤ICP备18096694号</a><br>
|
||||||
|
Licensed under an
|
||||||
<a target="_blank" href="http://www.apache.org/licenses/LICENSE-2.0">Apache License</a> –
|
<a target="_blank" href="http://www.apache.org/licenses/LICENSE-2.0">Apache License</a> –
|
||||||
<a href="privacy_policy.html" target="_blank">隐私策略</a>
|
<a href="privacy_policy.html" target="_blank">隐私策略</a>
|
||||||
</div>
|
</div>
|
||||||
@ -441,17 +464,15 @@
|
|||||||
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
|
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
<!-- built files will be auto injected -->
|
<!-- built files will be auto injected -->
|
||||||
<!-- baidu统计-->
|
|
||||||
<script>
|
<script>
|
||||||
var _hmt = _hmt || [];
|
var _hmt = _hmt || [];
|
||||||
(function() {
|
(function() {
|
||||||
var hm = document.createElement("script");
|
var hm = document.createElement("script");
|
||||||
hm.src = "https://hm.baidu.com/hm.js?dad4b4383b13eedea1ab45ee323df1c3";
|
hm.src = "https://hm.baidu.com/hm.js?20a1e7a201b42702c49074c87a1f1035";
|
||||||
var s = document.getElementsByTagName("script")[0];
|
var s = document.getElementsByTagName("script")[0];
|
||||||
s.parentNode.insertBefore(hm, s);
|
s.parentNode.insertBefore(hm, s);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<!-- baidu统计结束-->
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -1,90 +1,90 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="format-detection" content="telephone=no" />
|
||||||
|
<meta name="msapplication-tap-highlight" content="no" />
|
||||||
|
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
|
||||||
|
<meta name="renderer" content="webkit" />
|
||||||
|
<meta name="viewport" id="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width" />
|
||||||
|
<title> 隐私权政策</title>
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
<head>
|
* {
|
||||||
<meta charset="utf-8" />
|
margin: 0;
|
||||||
<meta name="format-detection" content="telephone=no" />
|
padding: 0;
|
||||||
<meta name="msapplication-tap-highlight" content="no" />
|
}
|
||||||
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
|
|
||||||
<meta name="renderer" content="webkit" />
|
|
||||||
<meta name="viewport" id="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width" />
|
|
||||||
<title> 隐私权政策</title>
|
|
||||||
<style>
|
|
||||||
html {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
.title {
|
||||||
margin: 0;
|
padding: 10px;
|
||||||
padding: 0;
|
font-size: 16px;
|
||||||
}
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.date-text {
|
||||||
padding: 10px;
|
text-align: right;
|
||||||
font-size: 16px;
|
padding-right: 20px;
|
||||||
color: #333;
|
color: #333;
|
||||||
text-align: center;
|
padding-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-text {
|
body {
|
||||||
text-align: right;
|
padding: 10px 10px 20px;
|
||||||
padding-right: 20px;
|
}
|
||||||
color: #333;
|
|
||||||
padding-bottom: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
.main-text {
|
||||||
padding: 10px 10px 20px;
|
padding: 10px 0;
|
||||||
}
|
text-indent: 20px;
|
||||||
|
color: #333;
|
||||||
.main-text {
|
font-size: 16px;
|
||||||
padding: 10px 0;
|
}
|
||||||
text-indent: 20px;
|
|
||||||
color: #333;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
text-indent: 20px;
|
|
||||||
line-height: 22px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<h3 class="title"> 隐私权政策 </h3>
|
|
||||||
<div class="content">
|
|
||||||
【Markdown编辑器】(以下简称“本站”)深知个人信息对您的重要性, 故不会特意收集个人信息。
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
请在使用本产品(或服务)前,仔细阅读并了解本《隐私权政策》。
|
|
||||||
</div>
|
|
||||||
<div class="main-text">
|
|
||||||
一、关于您的文件信息
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
个人文档都是存储在第三方,本站对所有第三方的文件都是在您授权之后,通过您的浏览器直接访问,并不会在本站后端获取和保存您的任何个人文件信息。
|
|
||||||
</div>
|
|
||||||
<div class="main-text">
|
|
||||||
二、关于您的用户信息
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
本站不存在注册行为,待您授权后,您在第三方平台上个人信息的获取仅仅是在您的浏览器中直接获取,并不会在本站后端获取和保存您的个人信息。
|
|
||||||
</div>
|
|
||||||
<div class="main-text">
|
|
||||||
三、其他
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
本站可能会更新本隐私政策,以反映本站的业务需求和适用法律的变化。在更新隐私政策时,我会通过此网站或其他合适的方式通知您。如果您继续使用本站的服务,则意味着您同意更新后的隐私政策。
|
|
||||||
</div>
|
|
||||||
<div class="main-text">
|
|
||||||
四、如何联系我
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
如果您对本隐私政策有任何疑问、意见或建议,可通过<a href="https://jonylee.top" target="_blank" title="个人主页-JonyLee的设计导航">个人主页</a>联系方式与我联系:
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
|
.content {
|
||||||
|
text-indent: 20px;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h3 class="title"> 隐私权政策 </h3>
|
||||||
|
<div class="content">
|
||||||
|
【StackEdit中文版】(以下简称“此站”)深知个人信息对您的重要性, 故不会特意收集个人信息。
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
请在使用我们的产品(或服务)前,仔细阅读并了解本《隐私权政策》。
|
||||||
|
</div>
|
||||||
|
<div class="main-text">
|
||||||
|
一、我们不会收集个人文档信息
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
个人文档都是存储在第三方,此站仅仅是通过前端缓存的token来获取或保存文档到第三方,并不会在本站后端保存用户的任何文档信息。
|
||||||
|
</div>
|
||||||
|
<div class="main-text">
|
||||||
|
二、我们不会收集个人第三方的Token或用户信息
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
本站不存在注册行为,不会收集个人信息,但是为了正常从第三方把Markdown文档读取或写入,有时需要借助本站后端获取第三方网站Token信息再返回给前端,但是本站承诺绝不会收集个人第三方网站的Token信息,只会在后端获取到之后返回给本站前端供前端使用。
|
||||||
|
</div>
|
||||||
|
<div class="main-text">
|
||||||
|
三、如何联系我们
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
如果您对本隐私政策有任何疑问、意见或建议,通过以下方式与我们联系:
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
邮箱:【mafgwo@163.com】
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
微信:【qicoding】
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
一般情况下,我们将在一周内回复。
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,181 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title>文章分享 - Markdown编辑器</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="canonical" href="https://md.jonylee.top/">
|
|
||||||
<link rel="icon" href="static/landing/favicon.ico" type="image/x-icon">
|
|
||||||
<link rel="shortcut icon" href="static/landing/favicon.ico" type="image/x-icon">
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="keywords" content="Markdown编辑器,StackEdit中文版,StackEdit汉化版,StackEdit,在线Markdown,笔记利器,Markdown笔记">
|
|
||||||
<meta name="description" content="支持直接将码云(Gitee)、GitHub、Gitea等仓库作为笔记存储仓库且支持拖拽/粘贴上传图片,并且可以直接在页面编辑同步和管理的Markdown编辑器。">
|
|
||||||
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
|
||||||
<meta name="baidu-site-verification" content="code-tGpn2BT069" />
|
|
||||||
<meta name="msvalidate.01" content="90A9558158543277BD284CFA054E7F5B" />
|
|
||||||
<link rel="stylesheet" href="style.css">
|
|
||||||
<style>
|
|
||||||
.share-header {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
background-color: #383c4a;
|
|
||||||
color: #fff;
|
|
||||||
padding: 10px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
z-index: 99999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-header .logo {
|
|
||||||
margin: 0 0 -8px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-header nav {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-header nav ul {
|
|
||||||
list-style-type: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-header nav li {
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-header nav a {
|
|
||||||
color: #fff;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-header nav a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.share-content {
|
|
||||||
transform: translateY(50px);
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script type="text/javascript">
|
|
||||||
function getQueryString(name) {
|
|
||||||
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
|
|
||||||
var r = window.location.search.substr(1).match(reg);
|
|
||||||
if (r != null) {
|
|
||||||
return unescape(r[2]);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendTagHtml(newdoc, tagName, targetParentEle) {
|
|
||||||
const tags = newdoc.getElementsByTagName(tagName);
|
|
||||||
if (!tags) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < tags.length; i++) {
|
|
||||||
targetParentEle.append(tags[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onload = function() {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
const gistId = getQueryString('id');
|
|
||||||
let accessToken = null;
|
|
||||||
const tokens = window.localStorage.getItem('data/tokens');
|
|
||||||
if (tokens) {
|
|
||||||
const tokensObj = JSON.parse(tokens);
|
|
||||||
if (tokensObj.data && tokensObj.data.gitee) {
|
|
||||||
const tokenArr = Object.keys(tokensObj.data.gitee).map(it => tokensObj.data.gitee[it]).filter(it => it && it.isLogin);
|
|
||||||
if (tokenArr.length > 0) {
|
|
||||||
accessToken = tokenArr[0].accessToken;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const url = `https://gitee.com/api/v5/gists/${gistId}`;
|
|
||||||
let urlWithToken = url;
|
|
||||||
let withToken = false;
|
|
||||||
if (accessToken) {
|
|
||||||
urlWithToken = `${url}?access_token=${accessToken}`;
|
|
||||||
withToken = true;
|
|
||||||
}
|
|
||||||
xhr.open('GET', urlWithToken);
|
|
||||||
xhr.onload = function() {
|
|
||||||
if (xhr.status === 200) {
|
|
||||||
const newdoc = document.implementation.createHTMLDocument("");
|
|
||||||
const body = JSON.parse(xhr.responseText);
|
|
||||||
for (let key in body.files) {
|
|
||||||
newdoc.documentElement.innerHTML = body.files[key].content;
|
|
||||||
}
|
|
||||||
const currHead = document.head;
|
|
||||||
// 头部
|
|
||||||
appendTagHtml(newdoc, 'style', currHead);
|
|
||||||
// title
|
|
||||||
document.title = newdoc.title + ' - StackEdit中文版';
|
|
||||||
// 内容
|
|
||||||
const shareContent = document.getElementsByClassName('share-content')[0];
|
|
||||||
shareContent.innerHTML = newdoc.body.innerHTML;
|
|
||||||
document.body.className = newdoc.body.className;
|
|
||||||
} else if (xhr.status === 403) {
|
|
||||||
const rateLimit = xhr.responseText && xhr.responseText.indexOf('Rate Limit') >= 0;
|
|
||||||
const appUri = `${window.location.protocol}//${window.location.host}/app`;
|
|
||||||
document.getElementById('div_info').innerHTML = `${rateLimit ? "请求太过频繁" : "无权限访问"},请登录 <a href="${appUri}" target="_brank">主文档空间</a> 后再刷新此页面!`;
|
|
||||||
} else if (xhr.status === 401) {
|
|
||||||
if (withToken) {
|
|
||||||
withToken = false;
|
|
||||||
xhr.open('GET', url);
|
|
||||||
xhr.send();
|
|
||||||
} else {
|
|
||||||
console.error('An error occurred: ' + xhr.status);
|
|
||||||
document.getElementById('div_info').innerHTML = `分享内容获取失败或已失效!请登录 <a href="${appUri}" target="_brank">主文档空间</a> 后再刷新此页面!`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.error('An error occurred: ' + xhr.status);
|
|
||||||
document.getElementById('div_info').innerHTML = `分享内容获取失败或已失效!请登录 <a href="${appUri}" target="_brank">主文档空间</a> 后再刷新此页面!`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="share-header">
|
|
||||||
<nav>
|
|
||||||
<a class="logo" href="https://md.jonylee.top" target="_blank">
|
|
||||||
<img src="static/landing/logo.svg" height="30px" />
|
|
||||||
</a>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://md.jonylee.top" target="_blank">首页</a></li>
|
|
||||||
<li><a href="https://md.jonylee.top/app" target="_blank">写笔记</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
<div class="share-content stackedit">
|
|
||||||
<div id="div_info" style="text-align: center; height: 600px;">文章加载中......</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
|
|
||||||
|
|
||||||
<!-- built files will be auto injected -->
|
|
||||||
<!-- baidu统计-->
|
|
||||||
<script>
|
|
||||||
var _hmt = _hmt || [];
|
|
||||||
(function() {
|
|
||||||
var hm = document.createElement("script");
|
|
||||||
hm.src = "https://hm.baidu.com/hm.js?dad4b4383b13eedea1ab45ee323df1c3";
|
|
||||||
var s = document.getElementsByTagName("script")[0];
|
|
||||||
s.parentNode.insertBefore(hm, s);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
<!-- baidu统计结束-->
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
@ -1,12 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<url>
|
<url>
|
||||||
<loc>https://md.jonylee.top/</loc>
|
<loc>https://stackedit.cn/</loc>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>1.0</priority>
|
<priority>1.0</priority>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://md.jonylee.top/app</loc>
|
<loc>https://stackedit.cn/app</loc>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>1.0</priority>
|
<priority>1.0</priority>
|
||||||
</url>
|
</url>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
<priority>0.8</priority>
|
<priority>0.8</priority>
|
||||||
</url>
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://md.jonylee.top/privacy_policy.html</loc>
|
<loc>https://stackedit.cn/privacy_policy.html</loc>
|
||||||
<changefreq>monthly</changefreq>
|
<changefreq>monthly</changefreq>
|
||||||
<priority>0.6</priority>
|
<priority>0.6</priority>
|
||||||
</url>
|
</url>
|
||||||
|
@ -1,216 +0,0 @@
|
|||||||
function init_preview_theme_activeblue() {
|
|
||||||
const style = document.createElement('style');
|
|
||||||
style.id = 'preview-theme-activeblue';
|
|
||||||
style.type = 'text/css';
|
|
||||||
style.innerHTML = "/** activeblue 灵动蓝\n \
|
|
||||||
*/\n \
|
|
||||||
.preview-theme--activeblue {\n \
|
|
||||||
color: #333;\n \
|
|
||||||
background-color: #fff;\n \
|
|
||||||
font-family: -apple-system,system-ui,BlinkMacSystemFont,Helvetica Neue,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Arial,sans-serif;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 标题的通用设置 */\n \
|
|
||||||
.preview-theme--activeblue h1,\n \
|
|
||||||
.preview-theme--activeblue h2,\n \
|
|
||||||
.preview-theme--activeblue h3,\n \
|
|
||||||
.preview-theme--activeblue h4,\n \
|
|
||||||
.preview-theme--activeblue h5,\n \
|
|
||||||
.preview-theme--activeblue h6 {\n \
|
|
||||||
padding: 30px 0;\n \
|
|
||||||
margin: 0;\n \
|
|
||||||
color: #135ce0;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 一级标题 */\n \
|
|
||||||
.preview-theme--activeblue h1 {\n \
|
|
||||||
position: relative;\n \
|
|
||||||
margin-top: 30px;\n \
|
|
||||||
margin-bottom: 10px;\n \
|
|
||||||
text-align: center;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 一级标题前缀,用来放背景图,支持透明度控制 */\n \
|
|
||||||
.preview-theme--activeblue h1 .prefix {\n \
|
|
||||||
display: inline-block;\n \
|
|
||||||
top: 0;\n \
|
|
||||||
width: 60px;\n \
|
|
||||||
height: 60px;\n \
|
|
||||||
background: url(https://imgs.qicoder.com/stackedit/ape_blue.svg);\n \
|
|
||||||
background-size: 100% 100%;\n \
|
|
||||||
opacity: .12;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 一级标题内容 */\n \
|
|
||||||
.preview-theme--activeblue h1 .content {\n \
|
|
||||||
font-size: 22px;\n \
|
|
||||||
display: block;\n \
|
|
||||||
margin-top: -36px;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 二级标题 */\n \
|
|
||||||
.preview-theme--activeblue h2 {\n \
|
|
||||||
position: relative;\n \
|
|
||||||
font-size: 20px;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 二级标题前缀,有兴趣加内容的可以魔改 */\n \
|
|
||||||
.preview-theme--activeblue h2 .prefix {\n \
|
|
||||||
\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 二级标题内容 */\n \
|
|
||||||
.preview-theme--activeblue h2 .content {\n \
|
|
||||||
border-left: 4px solid;\n \
|
|
||||||
padding-left: 10px;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 一二级标题之间间距控制一下 */\n \
|
|
||||||
.preview-theme--activeblue h1 + h2 {\n \
|
|
||||||
padding-top: 0;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 三级标题 */\n \
|
|
||||||
.preview-theme--activeblue h3 {\n \
|
|
||||||
font-size: 16px;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 段落 */\n \
|
|
||||||
.preview-theme--activeblue p {\n \
|
|
||||||
font-size: 16px;\n \
|
|
||||||
line-height: 2;\n \
|
|
||||||
font-weight: 400;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 段落间距控制 */\n \
|
|
||||||
.preview-theme--activeblue p+p {\n \
|
|
||||||
margin-top: 16px;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 无序列表 */\n \
|
|
||||||
.preview-theme--activeblue ul>li ul>li {\n \
|
|
||||||
list-style: circle;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 无序列表内容行高 */\n \
|
|
||||||
.preview-theme--activeblue li section {\n \
|
|
||||||
line-height: 2;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 引用 */\n \
|
|
||||||
.preview-theme--activeblue blockquote {\n \
|
|
||||||
border-left-color: #b2aec5 !important;\n \
|
|
||||||
background: #fff9f9 !important;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 引用文字 */\n \
|
|
||||||
.preview-theme--activeblue blockquote p {\n \
|
|
||||||
color: #666;\n \
|
|
||||||
line-height: 2;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 链接 */\n \
|
|
||||||
.preview-theme--activeblue a {\n \
|
|
||||||
color: #036aca;\n \
|
|
||||||
border-bottom: 0;\n \
|
|
||||||
font-weight: 400;\n \
|
|
||||||
text-decoration: none;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 加粗 */\n \
|
|
||||||
.preview-theme--activeblue strong {\n \
|
|
||||||
background: linear-gradient(to right ,#3299d2,#efbdb5);\n \
|
|
||||||
color: #fff;\n \
|
|
||||||
font-weight: 400;\n \
|
|
||||||
padding: 0 4px;\n \
|
|
||||||
display: inline-block;\n \
|
|
||||||
border-radius: 4px;\n \
|
|
||||||
margin: 0 2px;\n \
|
|
||||||
letter-spacing: 1px;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 加粗斜体 */\n \
|
|
||||||
.preview-theme--activeblue em strong {\n \
|
|
||||||
color: #fff;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 分隔线 */\n \
|
|
||||||
.preview-theme--activeblue hr {\n \
|
|
||||||
border-top: 1px solid #135ce0;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 图片描述文字,隐藏了,如果需要,请删除display */\n \
|
|
||||||
.preview-theme--activeblue figcaption {\n \
|
|
||||||
display: none;\n \
|
|
||||||
opacity: .6;\n \
|
|
||||||
margin-top: 12px;\n \
|
|
||||||
font-size: 12px;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 行内代码 */\n \
|
|
||||||
.preview-theme--activeblue p code,\n \
|
|
||||||
.preview-theme--activeblue li code,\n \
|
|
||||||
.preview-theme--activeblue table code {\n \
|
|
||||||
background-color: rgba(0,0,0,.05);\n \
|
|
||||||
color: #1394d8;\n \
|
|
||||||
padding: 2px 6px;\n \
|
|
||||||
word-break: normal;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 表格 */\n \
|
|
||||||
.preview-theme--activeblue table {\n \
|
|
||||||
border-spacing: 0;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/*\n \
|
|
||||||
* 表格内的单元格\n \
|
|
||||||
*/\n \
|
|
||||||
.preview-theme--activeblue table tr th {\n \
|
|
||||||
background-color: #d4f1ff;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 脚注文字 */\n \
|
|
||||||
.preview-theme--activeblue .footnote-word {\n \
|
|
||||||
color: #135ce0;\n \
|
|
||||||
font-weight: 400;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 脚注上标 */\n \
|
|
||||||
.preview-theme--activeblue .footnote-ref {\n \
|
|
||||||
color: #5ba1e2;\n \
|
|
||||||
font-weight: 400;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 参考资料 */\n \
|
|
||||||
.preview-theme--activeblue .footnotes-sep:before {\n \
|
|
||||||
text-align: center;\n \
|
|
||||||
color: #135ce0;\n \
|
|
||||||
content: \"参考\";\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 参考编号 */\n \
|
|
||||||
.preview-theme--activeblue .footnote-num {\n \
|
|
||||||
color: #666;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 参考文字 */\n \
|
|
||||||
.preview-theme--activeblue .footnote-item p { \n \
|
|
||||||
color: #999;\n \
|
|
||||||
font-weight: 700;\n \
|
|
||||||
font-style: italic;\n \
|
|
||||||
font-size: 13px;\n \
|
|
||||||
}\n \
|
|
||||||
\n \
|
|
||||||
/* 参考解释 */\n \
|
|
||||||
.preview-theme--activeblue .footnote-item p em {\n \
|
|
||||||
color: #3375e2;\n \
|
|
||||||
font-style: normal;\n \
|
|
||||||
margin-left: 4px;\n \
|
|
||||||
}\n \
|
|
||||||
.preview-theme--activeblue pre>code {\n \
|
|
||||||
background-color: #333;\n \
|
|
||||||
color: rgba(255,255,255,0.75);\n \
|
|
||||||
}";
|
|
||||||
document.head.appendChild(style);
|
|
||||||
}
|
|
||||||
init_preview_theme_activeblue();
|
|