commit
f489a611b0
@ -1,4 +1,4 @@
|
||||
FROM node:11.15.0
|
||||
FROM mafgwo/wkhtmltopdf-nodejs:11.15.0
|
||||
|
||||
RUN mkdir -p /opt/stackedit
|
||||
WORKDIR /opt/stackedit
|
||||
|
@ -14,7 +14,7 @@ StackEdit的作者可能因为什么原因,已经很久不维护了,Github
|
||||
### TODO: 关于后续的一些想法
|
||||
- 支持**Gitea**、**Gogs**两个轻量级且适于自建的Git仓库(毕竟Gitlab对机器配置要求较高)。想支持这两个主要也是考虑到其实很多公司已经禁用了Github或Gitee仓库,在公司都没法连上自己的Git仓库。
|
||||
- 汉化,毕竟大家最熟悉的还是母语,并且该编辑器功能页面也不多,汉化工作量并不会很大。
|
||||
- 替换主工作区为Gitee(原版本主工作区是Google Drive,国内只有fan墙才可以用)
|
||||
- 替换主文档空间为Gitee(原版本主文档空间是Google Drive,国内只有fan墙才可以用)
|
||||
- 引入mdnice,右边预览增加mdnice预览选项,主要含选主题(含mdnice常用20多个主题)、支持自定义主题、复制到公众号、复制到知乎、复制到稀土掘金等基本功能,便于喜欢写公众号、博客的同学可以更好更快的排版。
|
||||
- ... 另外,朋友们有好的想法也可以在Issue或者加我微信 qicoding 提给我。
|
||||
|
||||
@ -26,13 +26,14 @@ StackEdit的作者可能因为什么原因,已经很久不维护了,Github
|
||||
**Gogs目前无法支持,因为API目前不支持直接把Markdown推上去,如果后续Gogs的API支持了再添加**
|
||||
|
||||
**已汉化主要功能部分(2022-06-01)**
|
||||
对应Docker版本:5.15.5, tag: v5.15.5
|
||||
|
||||
**接下来修改主工作区为Gitee**
|
||||
|
||||
**已完成修改主文档空间为Gitee(2022-06-04)**
|
||||
对应Docker版本:5.15.6, tag: v5.15.6
|
||||
|
||||
|
||||
### 目前已部署地址
|
||||
https://edit.qicoder.com/
|
||||
https://stackedit.cn/
|
||||
|
||||
该地址可以作为试用或长期使用,本人承诺绝对没采集任何人的Token等敏感信息,不需要担心私有仓库泄漏。
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "StackEdit中文版",
|
||||
"description": "浏览器内 Markdown 编辑器",
|
||||
"description": "支持Gitee仓库的浏览器内 Markdown 编辑器",
|
||||
"version": "1.0.13",
|
||||
"manifest_version": 2,
|
||||
"container" : "GOOGLE_DRIVE",
|
||||
@ -15,10 +15,10 @@
|
||||
},
|
||||
"app": {
|
||||
"urls": [
|
||||
"https://edit.qicoder.com/"
|
||||
"https://stackedit.cn/"
|
||||
],
|
||||
"launch": {
|
||||
"web_url": "https://edit.qicoder.com/app"
|
||||
"web_url": "https://stackedit.cn/app"
|
||||
}
|
||||
},
|
||||
"offline_enabled": true,
|
||||
|
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>StackEdit中文版</title>
|
||||
<link rel="canonical" href="https://edit.qicoder.com/app">
|
||||
<link rel="canonical" href="https://stackedit.cn/app">
|
||||
<meta name="description" content="Free, open-source, full-featured Markdown editor.">
|
||||
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "stackedit",
|
||||
"version": "5.15.2",
|
||||
"version": "5.15.6",
|
||||
"description": "Free, open-source, full-featured Markdown editor",
|
||||
"author": "Benoit Schweblin",
|
||||
"license": "Apache-2.0",
|
||||
|
@ -37,6 +37,8 @@ module.exports = (app) => {
|
||||
|
||||
// Serve landing.html
|
||||
app.get('/', (req, res) => res.sendFile(resolvePath('static/landing/index.html')));
|
||||
// Serve privacy_policy.html
|
||||
app.get('/privacy_policy.html', (req, res) => res.sendFile(resolvePath('static/landing/privacy_policy.html')));
|
||||
// Serve sitemap.xml
|
||||
app.get('/sitemap.xml', (req, res) => res.sendFile(resolvePath('static/sitemap.xml')));
|
||||
// Serve callback.html
|
||||
|
196
server/pandoc.js
196
server/pandoc.js
@ -2,7 +2,6 @@
|
||||
const { spawn } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const tmp = require('tmp');
|
||||
const user = require('./user');
|
||||
const conf = require('./conf');
|
||||
|
||||
const outputFormats = {
|
||||
@ -42,108 +41,101 @@ exports.generate = (req, res) => {
|
||||
const outputFormat = Object.prototype.hasOwnProperty.call(outputFormats, req.query.format)
|
||||
? req.query.format
|
||||
: 'pdf';
|
||||
user.checkSponsor(req.query.idToken)
|
||||
.then((isSponsor) => {
|
||||
if (!isSponsor) {
|
||||
throw new Error('unauthorized');
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
tmp.file({
|
||||
postfix: `.${outputFormat}`,
|
||||
}, (err, filePath, fd, cleanupCallback) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve({
|
||||
filePath,
|
||||
cleanupCallback,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(({ filePath, cleanupCallback }) => new Promise((resolve, reject) => {
|
||||
const options = readJson(req.query.options);
|
||||
const metadata = readJson(req.query.metadata);
|
||||
const params = [];
|
||||
|
||||
params.push('--latex-engine=xelatex');
|
||||
params.push('--webtex=http://chart.apis.google.com/chart?cht=tx&chf=bg,s,FFFFFF00&chco=000000&chl=');
|
||||
if (options.toc) {
|
||||
params.push('--toc');
|
||||
}
|
||||
options.tocDepth = parseInt(options.tocDepth, 10);
|
||||
if (!Number.isNaN(options.tocDepth)) {
|
||||
params.push('--toc-depth', options.tocDepth);
|
||||
}
|
||||
options.highlightStyle = highlightStyles.includes(options.highlightStyle) ? options.highlightStyle : 'kate';
|
||||
params.push('--highlight-style', options.highlightStyle);
|
||||
Object.keys(metadata).forEach((key) => {
|
||||
params.push('-M', `${key}=${metadata[key]}`);
|
||||
});
|
||||
|
||||
let finished = false;
|
||||
|
||||
function onError(error) {
|
||||
finished = true;
|
||||
cleanupCallback();
|
||||
reject(error);
|
||||
}
|
||||
|
||||
const format = outputFormat === 'pdf' ? 'latex' : outputFormat;
|
||||
params.push('-f', 'json', '-t', format, '-o', filePath);
|
||||
const pandoc = spawn(conf.values.pandocPath, params, {
|
||||
stdio: [
|
||||
'pipe',
|
||||
'ignore',
|
||||
'pipe',
|
||||
],
|
||||
});
|
||||
let timeoutId = setTimeout(() => {
|
||||
timeoutId = null;
|
||||
pandoc.kill();
|
||||
}, 50000);
|
||||
pandoc.on('error', onError);
|
||||
pandoc.stdin.on('error', onError);
|
||||
pandoc.stderr.on('data', (data) => {
|
||||
pandocError += `${data}`;
|
||||
});
|
||||
pandoc.on('close', (code) => {
|
||||
if (!finished) {
|
||||
clearTimeout(timeoutId);
|
||||
if (!timeoutId) {
|
||||
res.statusCode = 408;
|
||||
cleanupCallback();
|
||||
reject(new Error('timeout'));
|
||||
} else if (code) {
|
||||
cleanupCallback();
|
||||
reject();
|
||||
} else {
|
||||
res.set('Content-Type', outputFormats[outputFormat]);
|
||||
const readStream = fs.createReadStream(filePath);
|
||||
readStream.on('open', () => readStream.pipe(res));
|
||||
readStream.on('close', () => cleanupCallback());
|
||||
readStream.on('error', () => {
|
||||
cleanupCallback();
|
||||
reject();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
req.pipe(pandoc.stdin);
|
||||
}))
|
||||
.catch((err) => {
|
||||
const message = err && err.message;
|
||||
if (message === 'unauthorized') {
|
||||
res.statusCode = 401;
|
||||
res.end('Unauthorized.');
|
||||
} else if (message === 'timeout') {
|
||||
res.statusCode = 408;
|
||||
res.end('Request timeout.');
|
||||
new Promise((resolve, reject) => {
|
||||
tmp.file({
|
||||
postfix: `.${outputFormat}`,
|
||||
}, (err, filePath, fd, cleanupCallback) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
res.statusCode = 400;
|
||||
res.end(pandocError || 'Unknown error.');
|
||||
resolve({
|
||||
filePath,
|
||||
cleanupCallback,
|
||||
});
|
||||
}
|
||||
});
|
||||
}).then(({ filePath, cleanupCallback }) => new Promise((resolve, reject) => {
|
||||
const options = readJson(req.query.options);
|
||||
const metadata = readJson(req.query.metadata);
|
||||
const params = [];
|
||||
|
||||
params.push('--pdf-engine=xelatex');
|
||||
params.push('--webtex=http://chart.apis.google.com/chart?cht=tx&chf=bg,s,FFFFFF00&chco=000000&chl=');
|
||||
if (options.toc) {
|
||||
params.push('--toc');
|
||||
}
|
||||
options.tocDepth = parseInt(options.tocDepth, 10);
|
||||
if (!Number.isNaN(options.tocDepth)) {
|
||||
params.push('--toc-depth', options.tocDepth);
|
||||
}
|
||||
options.highlightStyle = highlightStyles.includes(options.highlightStyle) ? options.highlightStyle : 'kate';
|
||||
params.push('--highlight-style', options.highlightStyle);
|
||||
Object.keys(metadata).forEach((key) => {
|
||||
params.push('-M', `${key}=${metadata[key]}`);
|
||||
});
|
||||
|
||||
let finished = false;
|
||||
|
||||
function onError(error) {
|
||||
finished = true;
|
||||
cleanupCallback();
|
||||
reject(error);
|
||||
}
|
||||
|
||||
const format = outputFormat === 'pdf' ? 'latex' : outputFormat;
|
||||
params.push('-f', 'json', '-t', format, '-o', filePath);
|
||||
const pandoc = spawn(conf.values.pandocPath, params, {
|
||||
stdio: [
|
||||
'pipe',
|
||||
'ignore',
|
||||
'pipe',
|
||||
],
|
||||
});
|
||||
let timeoutId = setTimeout(() => {
|
||||
timeoutId = null;
|
||||
pandoc.kill();
|
||||
}, 50000);
|
||||
pandoc.on('error', onError);
|
||||
pandoc.stdin.on('error', onError);
|
||||
pandoc.stderr.on('data', (data) => {
|
||||
pandocError += `${data}`;
|
||||
});
|
||||
pandoc.on('close', (code) => {
|
||||
if (!finished) {
|
||||
clearTimeout(timeoutId);
|
||||
if (!timeoutId) {
|
||||
res.statusCode = 408;
|
||||
cleanupCallback();
|
||||
reject(new Error('timeout'));
|
||||
} else if (code) {
|
||||
cleanupCallback();
|
||||
reject();
|
||||
} else {
|
||||
res.set('Content-Type', outputFormats[outputFormat]);
|
||||
const readStream = fs.createReadStream(filePath);
|
||||
readStream.on('open', () => readStream.pipe(res));
|
||||
readStream.on('close', () => cleanupCallback());
|
||||
readStream.on('error', () => {
|
||||
cleanupCallback();
|
||||
reject();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
req.pipe(pandoc.stdin);
|
||||
}))
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
const message = err && err.message;
|
||||
if (message === 'unauthorized') {
|
||||
res.statusCode = 401;
|
||||
res.end('Unauthorized.');
|
||||
} else if (message === 'timeout') {
|
||||
res.statusCode = 408;
|
||||
res.end('Request timeout.');
|
||||
} else {
|
||||
res.statusCode = 400;
|
||||
res.end(pandocError || 'Unknown error.');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
249
server/pdf.js
249
server/pdf.js
@ -2,7 +2,6 @@
|
||||
const { spawn } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const tmp = require('tmp');
|
||||
const user = require('./user');
|
||||
const conf = require('./conf');
|
||||
|
||||
/* eslint-disable no-var, prefer-arrow-callback, func-names */
|
||||
@ -51,135 +50,129 @@ const readJson = (str) => {
|
||||
|
||||
exports.generate = (req, res) => {
|
||||
let wkhtmltopdfError = '';
|
||||
user.checkSponsor(req.query.idToken)
|
||||
.then((isSponsor) => {
|
||||
if (!isSponsor) {
|
||||
throw new Error('unauthorized');
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
tmp.file((err, filePath, fd, cleanupCallback) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve({
|
||||
filePath,
|
||||
cleanupCallback,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(({ filePath, cleanupCallback }) => new Promise((resolve, reject) => {
|
||||
let finished = false;
|
||||
|
||||
function onError(err) {
|
||||
finished = true;
|
||||
cleanupCallback();
|
||||
new Promise((resolve, reject) => {
|
||||
tmp.file((err, filePath, fd, cleanupCallback) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
const options = readJson(req.query.options);
|
||||
const params = [];
|
||||
|
||||
// Margins
|
||||
const marginTop = parseInt(`${options.marginTop}`, 10);
|
||||
params.push('-T', Number.isNaN(marginTop) ? 25 : marginTop);
|
||||
const marginRight = parseInt(`${options.marginRight}`, 10);
|
||||
params.push('-R', Number.isNaN(marginRight) ? 25 : marginRight);
|
||||
const marginBottom = parseInt(`${options.marginBottom}`, 10);
|
||||
params.push('-B', Number.isNaN(marginBottom) ? 25 : marginBottom);
|
||||
const marginLeft = parseInt(`${options.marginLeft}`, 10);
|
||||
params.push('-L', Number.isNaN(marginLeft) ? 25 : marginLeft);
|
||||
|
||||
// Header
|
||||
if (options.headerCenter) {
|
||||
params.push('--header-center', `${options.headerCenter}`);
|
||||
}
|
||||
if (options.headerLeft) {
|
||||
params.push('--header-left', `${options.headerLeft}`);
|
||||
}
|
||||
if (options.headerRight) {
|
||||
params.push('--header-right', `${options.headerRight}`);
|
||||
}
|
||||
if (options.headerFontName) {
|
||||
params.push('--header-font-name', `${options.headerFontName}`);
|
||||
}
|
||||
if (options.headerFontSize) {
|
||||
params.push('--header-font-size', `${options.headerFontSize}`);
|
||||
}
|
||||
|
||||
// Footer
|
||||
if (options.footerCenter) {
|
||||
params.push('--footer-center', `${options.footerCenter}`);
|
||||
}
|
||||
if (options.footerLeft) {
|
||||
params.push('--footer-left', `${options.footerLeft}`);
|
||||
}
|
||||
if (options.footerRight) {
|
||||
params.push('--footer-right', `${options.footerRight}`);
|
||||
}
|
||||
if (options.footerFontName) {
|
||||
params.push('--footer-font-name', `${options.footerFontName}`);
|
||||
}
|
||||
if (options.footerFontSize) {
|
||||
params.push('--footer-font-size', `${options.footerFontSize}`);
|
||||
}
|
||||
|
||||
// Page size
|
||||
params.push('--page-size', !authorizedPageSizes.includes(options.pageSize) ? 'A4' : options.pageSize);
|
||||
|
||||
// Use a temp file as wkhtmltopdf can't access /dev/stdout on Amazon EC2 for some reason
|
||||
params.push('--run-script', `${waitForJavaScript.toString()}waitForJavaScript()`);
|
||||
params.push('--window-status', 'done');
|
||||
const wkhtmltopdf = spawn(conf.values.wkhtmltopdfPath, params.concat('-', filePath), {
|
||||
stdio: [
|
||||
'pipe',
|
||||
'ignore',
|
||||
'pipe',
|
||||
],
|
||||
});
|
||||
let timeoutId = setTimeout(function () {
|
||||
timeoutId = null;
|
||||
wkhtmltopdf.kill();
|
||||
}, 50000);
|
||||
wkhtmltopdf.on('error', onError);
|
||||
wkhtmltopdf.stdin.on('error', onError);
|
||||
wkhtmltopdf.stderr.on('data', (data) => {
|
||||
wkhtmltopdfError += `${data}`;
|
||||
});
|
||||
wkhtmltopdf.on('close', (code) => {
|
||||
if (!finished) {
|
||||
clearTimeout(timeoutId);
|
||||
if (!timeoutId) {
|
||||
cleanupCallback();
|
||||
reject(new Error('timeout'));
|
||||
} else if (code) {
|
||||
cleanupCallback();
|
||||
reject();
|
||||
} else {
|
||||
res.set('Content-Type', 'application/pdf');
|
||||
const readStream = fs.createReadStream(filePath);
|
||||
readStream.on('open', () => readStream.pipe(res));
|
||||
readStream.on('close', () => cleanupCallback());
|
||||
readStream.on('error', () => {
|
||||
cleanupCallback();
|
||||
reject();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
req.pipe(wkhtmltopdf.stdin);
|
||||
}))
|
||||
.catch((err) => {
|
||||
const message = err && err.message;
|
||||
if (message === 'unauthorized') {
|
||||
res.statusCode = 401;
|
||||
res.end('Unauthorized.');
|
||||
} else if (message === 'timeout') {
|
||||
res.statusCode = 408;
|
||||
res.end('Request timeout.');
|
||||
} else {
|
||||
res.statusCode = 400;
|
||||
res.end(wkhtmltopdfError || 'Unknown error.');
|
||||
resolve({
|
||||
filePath,
|
||||
cleanupCallback,
|
||||
});
|
||||
}
|
||||
});
|
||||
}).then(({ filePath, cleanupCallback }) => new Promise((resolve, reject) => {
|
||||
let finished = false;
|
||||
|
||||
function onError(err) {
|
||||
finished = true;
|
||||
cleanupCallback();
|
||||
reject(err);
|
||||
}
|
||||
const options = readJson(req.query.options);
|
||||
const params = [];
|
||||
|
||||
// Margins
|
||||
const marginTop = parseInt(`${options.marginTop}`, 10);
|
||||
params.push('-T', Number.isNaN(marginTop) ? 25 : marginTop);
|
||||
const marginRight = parseInt(`${options.marginRight}`, 10);
|
||||
params.push('-R', Number.isNaN(marginRight) ? 25 : marginRight);
|
||||
const marginBottom = parseInt(`${options.marginBottom}`, 10);
|
||||
params.push('-B', Number.isNaN(marginBottom) ? 25 : marginBottom);
|
||||
const marginLeft = parseInt(`${options.marginLeft}`, 10);
|
||||
params.push('-L', Number.isNaN(marginLeft) ? 25 : marginLeft);
|
||||
|
||||
// Header
|
||||
if (options.headerCenter) {
|
||||
params.push('--header-center', `${options.headerCenter}`);
|
||||
}
|
||||
if (options.headerLeft) {
|
||||
params.push('--header-left', `${options.headerLeft}`);
|
||||
}
|
||||
if (options.headerRight) {
|
||||
params.push('--header-right', `${options.headerRight}`);
|
||||
}
|
||||
if (options.headerFontName) {
|
||||
params.push('--header-font-name', `${options.headerFontName}`);
|
||||
}
|
||||
if (options.headerFontSize) {
|
||||
params.push('--header-font-size', `${options.headerFontSize}`);
|
||||
}
|
||||
|
||||
// Footer
|
||||
if (options.footerCenter) {
|
||||
params.push('--footer-center', `${options.footerCenter}`);
|
||||
}
|
||||
if (options.footerLeft) {
|
||||
params.push('--footer-left', `${options.footerLeft}`);
|
||||
}
|
||||
if (options.footerRight) {
|
||||
params.push('--footer-right', `${options.footerRight}`);
|
||||
}
|
||||
if (options.footerFontName) {
|
||||
params.push('--footer-font-name', `${options.footerFontName}`);
|
||||
}
|
||||
if (options.footerFontSize) {
|
||||
params.push('--footer-font-size', `${options.footerFontSize}`);
|
||||
}
|
||||
|
||||
// Page size
|
||||
params.push('--page-size', !authorizedPageSizes.includes(options.pageSize) ? 'A4' : options.pageSize);
|
||||
|
||||
// Use a temp file as wkhtmltopdf can't access /dev/stdout on Amazon EC2 for some reason
|
||||
params.push('--run-script', `${waitForJavaScript.toString()}waitForJavaScript()`);
|
||||
params.push('--window-status', 'done');
|
||||
const wkhtmltopdf = spawn(conf.values.wkhtmltopdfPath, params.concat('-', filePath), {
|
||||
stdio: [
|
||||
'pipe',
|
||||
'ignore',
|
||||
'pipe',
|
||||
],
|
||||
});
|
||||
let timeoutId = setTimeout(function () {
|
||||
timeoutId = null;
|
||||
wkhtmltopdf.kill();
|
||||
}, 50000);
|
||||
wkhtmltopdf.on('error', onError);
|
||||
wkhtmltopdf.stdin.on('error', onError);
|
||||
wkhtmltopdf.stderr.on('data', (data) => {
|
||||
wkhtmltopdfError += `${data}`;
|
||||
});
|
||||
wkhtmltopdf.on('close', (code) => {
|
||||
if (!finished) {
|
||||
clearTimeout(timeoutId);
|
||||
if (!timeoutId) {
|
||||
cleanupCallback();
|
||||
reject(new Error('timeout'));
|
||||
} else if (code) {
|
||||
cleanupCallback();
|
||||
reject();
|
||||
} else {
|
||||
res.set('Content-Type', 'application/pdf');
|
||||
const readStream = fs.createReadStream(filePath);
|
||||
readStream.on('open', () => readStream.pipe(res));
|
||||
readStream.on('close', () => cleanupCallback());
|
||||
readStream.on('error', () => {
|
||||
cleanupCallback();
|
||||
reject();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
req.pipe(wkhtmltopdf.stdin);
|
||||
}))
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
const message = err && err.message;
|
||||
if (message === 'unauthorized') {
|
||||
res.statusCode = 401;
|
||||
res.end('Unauthorized.');
|
||||
} else if (message === 'timeout') {
|
||||
res.statusCode = 408;
|
||||
res.end('Request timeout.');
|
||||
} else {
|
||||
res.statusCode = 400;
|
||||
res.end(wkhtmltopdfError || 'Unknown error.');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -4,10 +4,10 @@
|
||||
<button class="button-bar__button button-bar__button--navigation-bar-toggler button" :class="{ 'button-bar__button--on': layoutSettings.showNavigationBar }" v-if="!light" @click="toggleNavigationBar()" v-title="'切换导航栏'">
|
||||
<icon-navigation-bar></icon-navigation-bar>
|
||||
</button>
|
||||
<button class="button-bar__button button-bar__button--side-preview-toggler button" :class="{ 'button-bar__button--on': layoutSettings.showSidePreview }" tour-step-anchor="editor" @click="toggleSidePreview()" v-title="'切换侧面预览'">
|
||||
<button class="button-bar__button button-bar__button--side-preview-toggler button" :class="{ 'button-bar__button--on': layoutSettings.showSidePreview }" tour-step-anchor="editor" @click="toggleSidePreview()" v-title="'切换侧边预览'">
|
||||
<icon-side-preview></icon-side-preview>
|
||||
</button>
|
||||
<button class="button-bar__button button-bar__button--editor-toggler button" @click="toggleEditor(false)" v-title="'Reader mode'">
|
||||
<button class="button-bar__button button-bar__button--editor-toggler button" @click="toggleEditor(false)" v-title="'阅读模式'">
|
||||
<icon-eye></icon-eye>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="find-replace" @keydown.esc.stop="onEscape">
|
||||
<button class="find-replace__close-button button not-tabbable" @click="close()" v-title="'Close'">
|
||||
<button class="find-replace__close-button button not-tabbable" @click="close()" v-title="'关闭'">
|
||||
<icon-close></icon-close>
|
||||
</button>
|
||||
<div class="find-replace__row">
|
||||
|
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="modal" v-if="config" @keydown.esc.stop="onEscape" @keydown.tab="onTab" @focusin="onFocusInOut" @focusout="onFocusInOut">
|
||||
<div class="modal__sponsor-banner" v-if="!isSponsor">
|
||||
<!-- <div class="modal__sponsor-banner" v-if="!isSponsor">
|
||||
StackEdit is <a class="not-tabbable" target="_blank" href="https://github.com/mafgwo/stackedit/">open source</a>, please consider
|
||||
<a class="not-tabbable" href="javascript:void(0)" @click="sponsor">sponsoring</a> for just $5.
|
||||
</div>
|
||||
</div> -->
|
||||
<component v-if="currentModalComponent" :is="currentModalComponent"></component>
|
||||
<modal-inner v-else aria-label="Dialog">
|
||||
<div class="modal__content" v-html="simpleModal.contentHtml(config)"></div>
|
||||
@ -20,7 +20,7 @@ import { mapGetters } from 'vuex';
|
||||
import simpleModals from '../data/simpleModals';
|
||||
import editorSvc from '../services/editorSvc';
|
||||
import syncSvc from '../services/syncSvc';
|
||||
import googleHelper from '../services/providers/helpers/googleHelper';
|
||||
import giteeHelper from '../services/providers/helpers/giteeHelper';
|
||||
import store from '../store';
|
||||
|
||||
import ModalInner from './modals/common/ModalInner';
|
||||
@ -168,7 +168,7 @@ export default {
|
||||
if (!store.getters['workspace/sponsorToken']) {
|
||||
// User has to sign in
|
||||
await store.dispatch('modal/open', 'signInForSponsorship');
|
||||
await googleHelper.signin();
|
||||
await giteeHelper.signin();
|
||||
syncSvc.requestSync();
|
||||
}
|
||||
if (!store.getters.isSponsor) {
|
||||
|
@ -2,12 +2,12 @@
|
||||
<nav class="navigation-bar" :class="{'navigation-bar--editor': styles.showEditor && !revisionContent, 'navigation-bar--light': light}">
|
||||
<!-- Explorer -->
|
||||
<div class="navigation-bar__inner navigation-bar__inner--left navigation-bar__inner--button">
|
||||
<button class="navigation-bar__button navigation-bar__button--close button" v-if="light" @click="close()" v-title="'Close StackEdit'"><icon-check-circle></icon-check-circle></button>
|
||||
<button class="navigation-bar__button navigation-bar__button--close button" v-if="light" @click="close()" v-title="'关闭StackEdit'"><icon-check-circle></icon-check-circle></button>
|
||||
<button class="navigation-bar__button navigation-bar__button--explorer-toggler button" v-else tour-step-anchor="explorer" @click="toggleExplorer()" v-title="'切换资源管理器'"><icon-folder></icon-folder></button>
|
||||
</div>
|
||||
<!-- Side bar -->
|
||||
<div class="navigation-bar__inner navigation-bar__inner--right navigation-bar__inner--button">
|
||||
<a class="navigation-bar__button navigation-bar__button--stackedit button" v-if="light" href="app" target="_blank" v-title="'Open StackEdit'"><icon-provider provider-id="stackedit"></icon-provider></a>
|
||||
<a class="navigation-bar__button navigation-bar__button--stackedit button" v-if="light" href="app" target="_blank" v-title="'打开StackEdit'"><icon-provider provider-id="stackedit"></icon-provider></a>
|
||||
<button class="navigation-bar__button navigation-bar__button--stackedit button" v-else tour-step-anchor="menu" @click="toggleSideBar()" v-title="'切换侧边栏'"><icon-provider provider-id="stackedit"></icon-provider></button>
|
||||
</div>
|
||||
<div class="navigation-bar__inner navigation-bar__inner--right navigation-bar__inner--title flex flex--row">
|
||||
@ -22,15 +22,15 @@
|
||||
<input class="navigation-bar__title navigation-bar__title--input text-input" :class="{'navigation-bar__title--focus': titleFocus, 'navigation-bar__title--scrolling': titleScrolling}" :style="{width: titleWidth + 'px'}" @focus="editTitle(true)" @blur="editTitle(false)" @keydown.enter="submitTitle(false)" @keydown.esc.stop="submitTitle(true)" @mouseenter="titleHover = true" @mouseleave="titleHover = false" v-model="title">
|
||||
<!-- Sync/Publish -->
|
||||
<div class="flex flex--row" :class="{'navigation-bar__hidden': styles.hideLocations}">
|
||||
<a class="navigation-bar__button navigation-bar__button--location button" :class="{'navigation-bar__button--blink': location.id === currentLocation.id}" v-for="location in syncLocations" :key="location.id" :href="location.url" target="_blank" v-title="'Synchronized location'"><icon-provider :provider-id="location.providerId"></icon-provider></a>
|
||||
<a class="navigation-bar__button navigation-bar__button--location button" :class="{'navigation-bar__button--blink': location.id === currentLocation.id}" v-for="location in syncLocations" :key="location.id" :href="location.url" target="_blank" v-title="'同步位置'"><icon-provider :provider-id="location.providerId"></icon-provider></a>
|
||||
<button class="navigation-bar__button navigation-bar__button--sync button" :disabled="!isSyncPossible || isSyncRequested || offline" @click="requestSync" v-title="'立即同步'"><icon-sync></icon-sync></button>
|
||||
<a class="navigation-bar__button navigation-bar__button--location button" :class="{'navigation-bar__button--blink': location.id === currentLocation.id}" v-for="location in publishLocations" :key="location.id" :href="location.url" target="_blank" v-title="'Publish location'"><icon-provider :provider-id="location.providerId"></icon-provider></a>
|
||||
<a class="navigation-bar__button navigation-bar__button--location button" :class="{'navigation-bar__button--blink': location.id === currentLocation.id}" v-for="location in publishLocations" :key="location.id" :href="location.url" target="_blank" v-title="'发布位置'"><icon-provider :provider-id="location.providerId"></icon-provider></a>
|
||||
<button class="navigation-bar__button navigation-bar__button--publish button" :disabled="!publishLocations.length || isPublishRequested || offline" @click="requestPublish" v-title="'立即发布'"><icon-upload></icon-upload></button>
|
||||
</div>
|
||||
<!-- Revision -->
|
||||
<div class="flex flex--row" v-if="revisionContent">
|
||||
<button class="navigation-bar__button navigation-bar__button--revision navigation-bar__button--restore button" @click="restoreRevision">Restore</button>
|
||||
<button class="navigation-bar__button navigation-bar__button--revision button" @click="setRevisionContent()" v-title="'Close revision'"><icon-close></icon-close></button>
|
||||
<button class="navigation-bar__button navigation-bar__button--revision navigation-bar__button--restore button" @click="restoreRevision">恢复</button>
|
||||
<button class="navigation-bar__button navigation-bar__button--revision button" @click="setRevisionContent()" v-title="'关闭修订'"><icon-close></icon-close></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navigation-bar__inner navigation-bar__inner--edit-pagedownButtons">
|
||||
|
@ -9,7 +9,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!styles.showEditor" class="preview__corner">
|
||||
<button class="preview__button button" @click="toggleEditor(true)" v-title="'Edit file'">
|
||||
<button class="preview__button button" @click="toggleEditor(true)" v-title="'编辑文件'">
|
||||
<icon-pen></icon-pen>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="side-bar flex flex--column">
|
||||
<div class="side-title flex flex--row">
|
||||
<button v-if="panel !== 'menu'" class="side-title__button button" @click="setPanel('menu')" v-title="'Main menu'">
|
||||
<button v-if="panel !== 'menu'" class="side-title__button button" @click="setPanel('menu')" v-title="'主菜单'">
|
||||
<icon-dots-horizontal></icon-dots-horizontal>
|
||||
</button>
|
||||
<div class="side-title__title">
|
||||
{{panelName}}
|
||||
</div>
|
||||
<button class="side-title__button button" @click="toggleSideBar(false)" v-title="'Close side bar'">
|
||||
<button class="side-title__button button" @click="toggleSideBar(false)" v-title="'关闭侧边栏'">
|
||||
<icon-close></icon-close>
|
||||
</button>
|
||||
</div>
|
||||
@ -47,14 +47,14 @@ import store from '../store';
|
||||
|
||||
const panelNames = {
|
||||
menu: '菜单',
|
||||
workspaces: '工作区',
|
||||
workspaces: '文档空间',
|
||||
help: 'Markdown 帮助',
|
||||
toc: '目录',
|
||||
sync: '同步',
|
||||
publish: '发布',
|
||||
history: '文件历史',
|
||||
importExport: '导入/导出',
|
||||
workspaceBackups: '工作区备份',
|
||||
workspaceBackups: '文档空间备份',
|
||||
};
|
||||
|
||||
export default {
|
||||
|
@ -8,7 +8,7 @@
|
||||
<span v-for="stat in textStats" :key="stat.id">
|
||||
<span class="stat-panel__value">{{stat.value}}</span> {{stat.name}}
|
||||
</span>
|
||||
<span class="stat-panel__value">Ln {{line}}, Col {{column}}</span>
|
||||
<span class="stat-panel__value">第 {{line}} 行, 第 {{column}} 列</span>
|
||||
</div>
|
||||
<div class="stat-panel__block stat-panel__block--right">
|
||||
<span class="stat-panel__block-name">
|
||||
@ -43,14 +43,13 @@ export default {
|
||||
line: 0,
|
||||
column: 0,
|
||||
textStats: [
|
||||
new Stat('bytes', '[\\s\\S]'),
|
||||
new Stat('words', '\\S+'),
|
||||
new Stat('lines', '\n'),
|
||||
new Stat('字符', '[\\s\\S]'),
|
||||
new Stat('字数', '\\S'),
|
||||
new Stat('行数', '\n'),
|
||||
],
|
||||
htmlStats: [
|
||||
new Stat('characters', '\\S'),
|
||||
new Stat('words', '\\S+'),
|
||||
new Stat('paragraphs', '\\S.*'),
|
||||
new Stat('字数', '\\S'),
|
||||
new Stat('段落', '\\S.*'),
|
||||
],
|
||||
}),
|
||||
computed: mapGetters('layout', [
|
||||
|
@ -13,7 +13,7 @@
|
||||
<div class="tour-step__inner" v-else-if="step === 'editor'">
|
||||
<h2>您的Markdown编辑器</h2>
|
||||
<p>StackEdit实时将Markdown转换为HTML。</p>
|
||||
<p>点击 <icon-side-preview></icon-side-preview> 切换侧面预览</p>
|
||||
<p>点击 <icon-side-preview></icon-side-preview> 切换侧边预览</p>
|
||||
<div class="tour-step__button-bar">
|
||||
<button class="button" @click="finish">跳过</button>
|
||||
<button class="button button--resolve" @click="next">下一步</button>
|
||||
@ -21,7 +21,7 @@
|
||||
</div>
|
||||
<div class="tour-step__inner" v-else-if="step === 'explorer'">
|
||||
<h2>文件资源管理器</h2>
|
||||
<p>StackEdit可以管理工作区中的多个文件和文件夹。</p>
|
||||
<p>StackEdit可以管理文档空间中的多个文件和文件夹。</p>
|
||||
<p>点击 <icon-folder></icon-folder> 打开文件资源管理器。</p>
|
||||
<div class="tour-step__button-bar">
|
||||
<button class="button" @click="finish">跳过</button>
|
||||
@ -30,7 +30,7 @@
|
||||
</div>
|
||||
<div class="tour-step__inner" v-else-if="step === 'menu'">
|
||||
<h2>更多!</h2>
|
||||
<p>StackEdit还可以同步和发布文件,管理协作工作区...</p>
|
||||
<p>StackEdit还可以同步和发布文件,管理协作文档空间...</p>
|
||||
<p>点击 <icon-provider provider-id="stackedit"></icon-provider> 浏览菜单。</p>
|
||||
<div class="tour-step__button-bar">
|
||||
<button class="button" @click="finish">跳过</button>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<div class="comment__user-image">
|
||||
<user-image :user-id="comment.sub"></user-image>
|
||||
</div>
|
||||
<button class="comment__remove-button button" v-title="'Remove comment'" @click="removeComment">
|
||||
<button class="comment__remove-button button" v-title="'删除评论'" @click="removeComment">
|
||||
<icon-delete></icon-delete>
|
||||
</button>
|
||||
<user-name :user-id="comment.sub"></user-name>
|
||||
|
@ -4,18 +4,18 @@
|
||||
<div class="current-discussion__inner">
|
||||
<div class="flex flex--row flex--space-between">
|
||||
<div class="current-discussion__buttons flex flex--row flex--end">
|
||||
<button class="current-discussion__button button" v-if="showNext" @click="goToDiscussion(previousDiscussionId)" v-title="'Previous discussion'">
|
||||
<button class="current-discussion__button button" v-if="showNext" @click="goToDiscussion(previousDiscussionId)" v-title="'上一个讨论'">
|
||||
<icon-arrow-left></icon-arrow-left>
|
||||
</button>
|
||||
<button class="current-discussion__button current-discussion__button--rotate button" v-if="showNext" @click="goToDiscussion(nextDiscussionId)" v-title="'Next discussion'">
|
||||
<button class="current-discussion__button current-discussion__button--rotate button" v-if="showNext" @click="goToDiscussion(nextDiscussionId)" v-title="'下一个讨论'">
|
||||
<icon-arrow-left></icon-arrow-left>
|
||||
</button>
|
||||
</div>
|
||||
<div class="current-discussion__buttons flex flex--row flex--end">
|
||||
<button class="current-discussion__button current-discussion__button--remove button" v-if="showRemove" @click="removeDiscussion" v-title="'Remove discussion'">
|
||||
<button class="current-discussion__button current-discussion__button--remove button" v-if="showRemove" @click="removeDiscussion" v-title="'删除讨论'">
|
||||
<icon-delete></icon-delete>
|
||||
</button>
|
||||
<button class="current-discussion__button button" @click="setCurrentDiscussionId()" v-title="'Close discussion'">
|
||||
<button class="current-discussion__button button" @click="setCurrentDiscussionId()" v-title="'关闭讨论'">
|
||||
<icon-close></icon-close>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a class="new-discussion-button" href="javascript:void(0)" v-if="coordinates" :style="{top: coordinates.top + 'px'}" v-title="'Start a discussion'" @mousedown.stop.prevent @click="createNewDiscussion(selection)">
|
||||
<a class="new-discussion-button" href="javascript:void(0)" v-if="coordinates" :style="{top: coordinates.top + 'px'}" v-title="'开始讨论'" @mousedown.stop.prevent @click="createNewDiscussion(selection)">
|
||||
<icon-message></icon-message>
|
||||
</a>
|
||||
</template>
|
||||
|
@ -14,8 +14,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment__buttons flex flex--row flex--end">
|
||||
<button class="comment__button button" @click="cancelNewComment">Cancel</button>
|
||||
<button class="comment__button button" @click="addComment">Ok</button>
|
||||
<button class="comment__button button" @click="cancelNewComment">取消</button>
|
||||
<button class="comment__button button" @click="addComment">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a class="new-discussion-button" href="javascript:void(0)" v-if="coordinates" :style="{top: coordinates.top + 'px'}" v-title="'Start a discussion'" @mousedown.stop.prevent @click="createNewDiscussion(selection)">
|
||||
<a class="new-discussion-button" href="javascript:void(0)" v-if="coordinates" :style="{top: coordinates.top + 'px'}" v-title="'开始讨论'" @mousedown.stop.prevent @click="createNewDiscussion(selection)">
|
||||
<icon-message></icon-message>
|
||||
</a>
|
||||
</template>
|
||||
|
@ -8,7 +8,7 @@
|
||||
</option>
|
||||
</select>
|
||||
</p>
|
||||
<p v-if="!historyContext">同步 <b>{{currentFileName}}</b> 以启用修订历史 或者 <a href="javascript:void(0)" @click="signin">登录 Google</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="!revisionsWithSpacer.length"><b>{{currentFileName}}</b> 没有历史版本.</p>
|
||||
<div class="menu-entry menu-entry--info flex flex--row flex--align-center" v-else>
|
||||
@ -53,7 +53,7 @@ import UserName from '../UserName';
|
||||
import EditorClassApplier from '../common/EditorClassApplier';
|
||||
import PreviewClassApplier from '../common/PreviewClassApplier';
|
||||
import utils from '../../services/utils';
|
||||
import googleHelper from '../../services/providers/helpers/googleHelper';
|
||||
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
||||
import syncSvc from '../../services/syncSvc';
|
||||
import store from '../../store';
|
||||
import badgeSvc from '../../services/badgeSvc';
|
||||
@ -166,7 +166,7 @@ export default {
|
||||
]),
|
||||
async signin() {
|
||||
try {
|
||||
await googleHelper.signin();
|
||||
await giteeHelper.signin();
|
||||
syncSvc.requestSync();
|
||||
} catch (e) {
|
||||
// Cancel
|
||||
|
@ -33,14 +33,14 @@
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="exportPdf">
|
||||
<icon-download slot="icon"></icon-download>
|
||||
<div><div class="menu-entry__label" :class="{'menu-entry__label--warning': !isSponsor}">赞助商</div> 导出为 HTML PDF</div>
|
||||
<div>导出为 HTML PDF</div>
|
||||
<span>从HTML模板生成PDF。</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="exportPandoc">
|
||||
<!-- <menu-entry @click.native="exportPandoc">
|
||||
<icon-download slot="icon"></icon-download>
|
||||
<div><div class="menu-entry__label" :class="{'menu-entry__label--warning': !isSponsor}">赞助商</div> 导出为 HTML Pandoc</div>
|
||||
<div>导出为 HTML Pandoc</div>
|
||||
<span>转换为PDF、Word、EPUB...</span>
|
||||
</menu-entry>
|
||||
</menu-entry> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -5,14 +5,14 @@
|
||||
<div class="menu-entry__icon menu-entry__icon--image">
|
||||
<user-image :user-id="userId"></user-image>
|
||||
</div>
|
||||
<span>Signed in as <b>{{loginToken.name}}</b>.</span>
|
||||
<span>登录名为<b>{{loginToken.name}}</b>。</span>
|
||||
</div>
|
||||
<div class="menu-entry menu-entry--info flex flex--row flex--align-center" v-if="syncToken">
|
||||
<div class="menu-entry__icon menu-entry__icon--image">
|
||||
<icon-provider :provider-id="currentWorkspace.providerId"></icon-provider>
|
||||
</div>
|
||||
<span v-if="currentWorkspace.providerId === 'googleDriveAppData'">
|
||||
<b>{{currentWorkspace.name}}</b> 与您的 Google Drive 应用数据文件夹同步。
|
||||
<span v-if="currentWorkspace.providerId === 'giteeAppData'">
|
||||
<b>{{currentWorkspace.name}}</b> 与您的 Gitee 默认文档空间仓库同步。
|
||||
</span>
|
||||
<span v-else-if="currentWorkspace.providerId === 'googleDriveWorkspace'">
|
||||
<b>{{currentWorkspace.name}}</b> 与 <a :href="workspaceLocationUrl" target="_blank">Google Drive 文件夹</a>同步。
|
||||
@ -42,13 +42,13 @@
|
||||
</div>
|
||||
<menu-entry v-if="!loginToken" @click.native="signin">
|
||||
<icon-login slot="icon"></icon-login>
|
||||
<div>使用 Google 登录</div>
|
||||
<span>同步您的主工作区并解锁功能。</span>
|
||||
<div>使用 Gitee 登录</div>
|
||||
<span>同步您的主文档空间并解锁功能。</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="setPanel('workspaces')">
|
||||
<icon-database slot="icon"></icon-database>
|
||||
<div><div class="menu-entry__label menu-entry__label--count" v-if="workspaceCount">{{workspaceCount}}</div> 工作区</div>
|
||||
<span>切换到另一个工作区。</span>
|
||||
<div><div class="menu-entry__label menu-entry__label--count" v-if="workspaceCount">{{workspaceCount}}</div> 文档空间</div>
|
||||
<span>切换到另一个文档空间。</span>
|
||||
</menu-entry>
|
||||
<hr>
|
||||
<menu-entry @click.native="setPanel('sync')">
|
||||
@ -97,8 +97,8 @@
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="accounts">
|
||||
<icon-key slot="icon"></icon-key>
|
||||
<div><div class="menu-entry__label menu-entry__label--count">{{accountCount}}</div> 账户</div>
|
||||
<span>管理对您的外部帐户的访问。</span>
|
||||
<div><div class="menu-entry__label menu-entry__label--count">{{accountCount}}</div> 账号</div>
|
||||
<span>管理对您的外部账号的访问。</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="templates">
|
||||
<icon-code-braces slot="icon"></icon-code-braces>
|
||||
@ -113,7 +113,7 @@
|
||||
<hr>
|
||||
<menu-entry @click.native="setPanel('workspaceBackups')">
|
||||
<icon-content-save slot="icon"></icon-content-save>
|
||||
工作区备份
|
||||
文档空间备份
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="reset">
|
||||
<icon-logout slot="icon"></icon-logout>
|
||||
@ -131,7 +131,7 @@ import { mapGetters, mapActions } from 'vuex';
|
||||
import MenuEntry from './common/MenuEntry';
|
||||
import providerRegistry from '../../services/providers/common/providerRegistry';
|
||||
import UserImage from '../UserImage';
|
||||
import googleHelper from '../../services/providers/helpers/googleHelper';
|
||||
import giteeHelper from '../../services/providers/helpers/giteeHelper';
|
||||
import syncSvc from '../../services/syncSvc';
|
||||
import userSvc from '../../services/userSvc';
|
||||
import store from '../../store';
|
||||
@ -183,7 +183,7 @@ export default {
|
||||
}),
|
||||
async signin() {
|
||||
try {
|
||||
await googleHelper.signin();
|
||||
await giteeHelper.signin();
|
||||
syncSvc.requestSync();
|
||||
} catch (e) {
|
||||
// Cancel
|
||||
|
@ -18,7 +18,7 @@
|
||||
</menu-entry>
|
||||
</div>
|
||||
<div class="side-bar__info" v-else-if="noToken">
|
||||
<p>您必须链接一个帐户才能开始发布文件。</p>
|
||||
<p>您必须链接一个账号才能开始发布文件。</p>
|
||||
</div>
|
||||
<hr>
|
||||
<div v-for="token in bloggerTokens" :key="'blogger-' + token.sub">
|
||||
|
@ -18,7 +18,7 @@
|
||||
</menu-entry>
|
||||
</div>
|
||||
<div class="side-bar__info" v-else-if="noToken">
|
||||
<p>您必须链接一个帐户才能开始同步文件。</p>
|
||||
<p>您必须链接一个账号才能开始同步文件。</p>
|
||||
</div>
|
||||
<hr>
|
||||
<div v-for="token in dropboxTokens" :key="token.sub">
|
||||
|
@ -6,12 +6,12 @@
|
||||
<icon-content-save></icon-content-save>
|
||||
</div>
|
||||
<div class="flex flex--column">
|
||||
导入工作区备份
|
||||
导入文档空间备份
|
||||
</div>
|
||||
</label>
|
||||
<menu-entry @click.native="exportWorkspace">
|
||||
<icon-content-save slot="icon"></icon-content-save>
|
||||
导出工作区备份
|
||||
导出文档空间备份
|
||||
</menu-entry>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -2,8 +2,8 @@
|
||||
<div class="side-bar__panel side-bar__panel--menu">
|
||||
<menu-entry @click.native="manageWorkspaces">
|
||||
<icon-database slot="icon"></icon-database>
|
||||
<div><div class="menu-entry__label menu-entry__label--count">{{workspaceCount}}</div> 管理工作区</div>
|
||||
<span>列出、重命名、删除工作区</span>
|
||||
<div><div class="menu-entry__label menu-entry__label--count">{{workspaceCount}}</div> 管理文档空间</div>
|
||||
<span>列出、重命名、删除文档空间</span>
|
||||
</menu-entry>
|
||||
<hr>
|
||||
<div class="workspace" v-for="(workspace, id) in workspacesById" :key="id">
|
||||
@ -15,27 +15,27 @@
|
||||
<hr>
|
||||
<menu-entry @click.native="addGithubWorkspace">
|
||||
<icon-provider slot="icon" provider-id="githubWorkspace"></icon-provider>
|
||||
<span>新增 <b>GitHub</b> 工作区</span>
|
||||
<span>新增 <b>GitHub</b> 文档空间</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGiteeWorkspace">
|
||||
<icon-provider slot="icon" provider-id="giteeWorkspace"></icon-provider>
|
||||
<span>新增 <b>Gitee</b> 工作区</span>
|
||||
<span>新增 <b>Gitee</b> 文档空间</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGitlabWorkspace">
|
||||
<icon-provider slot="icon" provider-id="gitlabWorkspace"></icon-provider>
|
||||
<span>新增 <b>GitLab</b> 工作区</span>
|
||||
<span>新增 <b>GitLab</b> 文档空间</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGiteaWorkspace">
|
||||
<icon-provider slot="icon" provider-id="giteaWorkspace"></icon-provider>
|
||||
<span>新增 <b>Gitea</b> 工作区</span>
|
||||
<span>新增 <b>Gitea</b> 文档空间</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGoogleDriveWorkspace">
|
||||
<icon-provider slot="icon" provider-id="googleDriveWorkspace"></icon-provider>
|
||||
<span>新增 <b>Google Drive</b> 工作区</span>
|
||||
<span>新增 <b>Google Drive</b> 文档空间</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addCouchdbWorkspace">
|
||||
<icon-provider slot="icon" provider-id="couchdbWorkspace"></icon-provider>
|
||||
<span>新增 <b>CouchDB</b> 工作区</span>
|
||||
<span>新增 <b>CouchDB</b> 文档空间</span>
|
||||
</menu-entry>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<a target="_blank" href="#">Chrome 应用</a> — <a target="_blank" href="#">Chrome 扩展</a>
|
||||
<br>
|
||||
<hr>
|
||||
<small>© 2013-2022 StackEdit中文版<br>v{{version}}</small>
|
||||
<small>© 2022 StackEdit中文版<br>v{{version}}</small>
|
||||
<h3>常见问题解答</h3>
|
||||
<div class="faq" v-html="faq"></div>
|
||||
<div class="modal__info">
|
||||
|
@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<modal-inner class="modal__inner-1--account-management" aria-label="Manage external accounts">
|
||||
<modal-inner class="modal__inner-1--account-management" aria-label="管理外部账号">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-key></icon-key>
|
||||
</div>
|
||||
<p v-if="entries.length">StackEdit has access to the following external accounts:</p>
|
||||
<p v-else>StackEdit has no access to any external account yet.</p>
|
||||
<p v-if="entries.length">Stackedit可以访问以下外部账号:</p>
|
||||
<p v-else>Stackedit尚未访问任何外部账号。</p>
|
||||
<div>
|
||||
<div class="account-entry flex flex--column" v-for="entry in entries" :key="entry.token.sub">
|
||||
<div class="account-entry__header flex flex--row flex--align-center">
|
||||
@ -16,14 +16,14 @@
|
||||
{{entry.name}}
|
||||
</div>
|
||||
<div class="account-entry__buttons flex flex--row flex--center">
|
||||
<button class="account-entry__button button" @click="remove(entry)" v-title="'Remove access'">
|
||||
<button class="account-entry__button button" @click="remove(entry)" v-title="'删除访问'">
|
||||
<icon-delete></icon-delete>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="account-entry__row">
|
||||
<span class="account-entry__field" v-if="entry.userId">
|
||||
<b>User ID:</b>
|
||||
<b>用户ID:</b>
|
||||
{{entry.userId}}
|
||||
</span>
|
||||
<span class="account-entry__field" v-if="entry.url">
|
||||
@ -31,7 +31,7 @@
|
||||
{{entry.url}}
|
||||
</span>
|
||||
<span class="account-entry__field" v-if="entry.scopes">
|
||||
<b>Scopes:</b>
|
||||
<b>权限范围:</b>
|
||||
{{entry.scopes.join(', ')}}
|
||||
</span>
|
||||
</div>
|
||||
@ -39,47 +39,47 @@
|
||||
</div>
|
||||
<menu-entry @click.native="addBloggerAccount">
|
||||
<icon-provider slot="icon" provider-id="blogger"></icon-provider>
|
||||
<span>Add Blogger account</span>
|
||||
<span>添加Blogger账号</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addDropboxAccount">
|
||||
<icon-provider slot="icon" provider-id="dropbox"></icon-provider>
|
||||
<span>Add Dropbox account</span>
|
||||
<span>添加Dropbox账号</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGithubAccount">
|
||||
<icon-provider slot="icon" provider-id="github"></icon-provider>
|
||||
<span>Add GitHub account</span>
|
||||
<span>添加GitHub账号</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGiteeAccount">
|
||||
<icon-provider slot="icon" provider-id="gitee"></icon-provider>
|
||||
<span>Add Gitee account</span>
|
||||
<span>添加Gitee账号</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGitlabAccount">
|
||||
<icon-provider slot="icon" provider-id="gitlab"></icon-provider>
|
||||
<span>Add GitLab account</span>
|
||||
<span>添加GitLab账号</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGiteaAccount">
|
||||
<icon-provider slot="icon" provider-id="gitea"></icon-provider>
|
||||
<span>Add Gitea account</span>
|
||||
<span>添加Gitea账号</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGoogleDriveAccount">
|
||||
<icon-provider slot="icon" provider-id="googleDrive"></icon-provider>
|
||||
<span>Add Google Drive account</span>
|
||||
<span>添加Google Drive账号</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGooglePhotosAccount">
|
||||
<icon-provider slot="icon" provider-id="googlePhotos"></icon-provider>
|
||||
<span>Add Google Photos account</span>
|
||||
<span>添加Google Photos账号</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addWordpressAccount">
|
||||
<icon-provider slot="icon" provider-id="wordpress"></icon-provider>
|
||||
<span>Add WordPress account</span>
|
||||
<span>添加WordPress账号</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addZendeskAccount">
|
||||
<icon-provider slot="icon" provider-id="zendesk"></icon-provider>
|
||||
<span>Add Zendesk account</span>
|
||||
<span>添加Zendesk账号</span>
|
||||
</menu-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button button--resolve" @click="config.resolve()">Close</button>
|
||||
<button class="button button--resolve" @click="config.resolve()">关闭</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,18 +1,18 @@
|
||||
<template>
|
||||
<modal-inner class="modal__inner-1--badge-management" aria-label="Manage badges">
|
||||
<modal-inner class="modal__inner-1--badge-management" aria-label="管理徽章">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-seal></icon-seal>
|
||||
</div>
|
||||
<p v-if="badgeCount > 1">{{badgeCount}} badges earned</p>
|
||||
<p v-else>{{badgeCount}} badge earned</p>
|
||||
<p v-if="badgeCount > 1">获得了{{badgeCount}}徽章</p>
|
||||
<p v-else>获得了{{badgeCount}}徽章</p>
|
||||
<div class="badge-entry" v-for="badge in badgeTree" :key="badge.featureId">
|
||||
<div class="flex flex--row">
|
||||
<icon-seal class="badge-entry__icon" :class="{'badge-entry__icon--earned': badge.isEarned, 'badge-entry__icon--some-earned': badge.hasSomeEarned}"></icon-seal>
|
||||
<div>
|
||||
<span class="badge-entry__name" :class="{'badge-entry__name--earned': badge.isEarned, 'badge-entry__name--some-earned': badge.hasSomeEarned}">{{badge.name}}</span>
|
||||
<span class="badge-entry__description">— {{badge.description}}</span>
|
||||
<a href="javascript:void(0)" v-if="!shown[badge.featureId]" @click="show(badge.featureId)">Show</a>
|
||||
<a href="javascript:void(0)" v-if="!shown[badge.featureId]" @click="show(badge.featureId)">展开</a>
|
||||
<div class="badge-entry" v-else v-for="child in badge.children" :key="child.featureId">
|
||||
<div class="flex flex--row">
|
||||
<icon-seal class="badge-entry__icon" :class="{'badge-entry__icon--earned': child.isEarned}"></icon-seal>
|
||||
@ -27,7 +27,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button button--resolve" @click="config.resolve()">Close</button>
|
||||
<button class="button button--resolve" @click="config.resolve()">关闭</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<modal-inner class="modal__inner-1--file-properties" aria-label="File properties">
|
||||
<modal-inner class="modal__inner-1--file-properties" aria-label="文件属性">
|
||||
<div class="modal__content">
|
||||
<div class="tabs flex flex--row">
|
||||
<tab :active="tab === 'simple'" @click="setSimpleTab()">
|
||||
Simple properties
|
||||
简单属性
|
||||
</tab>
|
||||
<tab :active="tab === 'yaml'" @click="setYamlTab()">
|
||||
YAML properties
|
||||
YAML属性
|
||||
</tab>
|
||||
</div>
|
||||
<div v-if="tab === 'simple'">
|
||||
<div class="modal__title">Extensions</div>
|
||||
<div class="modal__sub-title">Configure the Markdown engine.</div>
|
||||
<div class="modal__title">扩展</div>
|
||||
<div class="modal__sub-title">配置Markdown引擎。</div>
|
||||
<form-entry label="Preset">
|
||||
<select slot="field" class="textfield" v-model="preset" @keydown.enter="resolve()">
|
||||
<option v-for="(preset, id) in presets" :key="id" :value="preset">
|
||||
@ -19,8 +19,8 @@
|
||||
</option>
|
||||
</select>
|
||||
</form-entry>
|
||||
<div class="modal__title">Metadata</div>
|
||||
<div class="modal__sub-title">Add info to your publications (Wordpress, Blogger...).</div>
|
||||
<div class="modal__title">元数据</div>
|
||||
<div class="modal__sub-title">将信息添加到您的发布(WordPress,Blogger ...)。</div>
|
||||
<form-entry label="Title">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="title" @keydown.enter="resolve()">
|
||||
</form-entry>
|
||||
@ -42,7 +42,7 @@
|
||||
<form-entry label="Status">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="status" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> draft
|
||||
<b>示例:</b>草稿
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Date" info="YYYY-MM-DD">
|
||||
@ -58,13 +58,13 @@
|
||||
</div>
|
||||
<div class="modal__error modal__error--file-properties">{{error}}</div>
|
||||
<div class="modal__info modal__info--multiline">
|
||||
<p><strong>ProTip:</strong> You can manually toggle extensions:</p>
|
||||
<p><strong>提示:</strong> 您可以手动切换扩展名:</p>
|
||||
<pre class=" language-yaml"><code class="prism language-yaml"><span class="token key atrule">extensions</span><span class="token punctuation">:</span>
|
||||
<span class="token key atrule">emoji</span><span class="token punctuation">:</span>
|
||||
<span class="token comment"># Enable emoji shortcuts like :) :-(</span>
|
||||
<span class="token comment"># 启用表情符号快捷方式如 :) :-(</span>
|
||||
<span class="token key atrule">shortcuts</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
|
||||
</code></pre>
|
||||
<p>Use preset <code>zero</code> to make your own configuration:</p>
|
||||
<p>使用预设<code>zero</code>制作自己的配置:</p>
|
||||
<pre class=" language-yaml"><code class="prism language-yaml"><span class="token key atrule">extensions</span><span class="token punctuation">:</span>
|
||||
<span class="token key atrule">preset</span><span class="token punctuation">:</span> zero
|
||||
<span class="token key atrule">markdown</span><span class="token punctuation">:</span>
|
||||
@ -72,13 +72,13 @@
|
||||
<span class="token key atrule">katex</span><span class="token punctuation">:</span>
|
||||
<span class="token key atrule">enabled</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
|
||||
</code></pre>
|
||||
<p>For the full list of options, see <a href="https://github.com/mafgwo/stackedit/blob/master/src/data/presets.js" target="_blank">here</a>.</p>
|
||||
<p>有关选项的完整列表,请参阅 <a href="https://gitee.com/mafgwo/stackedit/blob/master/src/data/presets.js" target="_blank">这里</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,22 +1,22 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Export to HTML">
|
||||
<modal-inner aria-label="导出到HTML">
|
||||
<div class="modal__content">
|
||||
<p>Please choose a template for your <b>HTML export</b>.</p>
|
||||
<form-entry label="Template">
|
||||
<p>请为您的<b> HTML导出</b>选择模板。</p>
|
||||
<form-entry label="模板">
|
||||
<select class="textfield" slot="field" 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">Configure templates</a>
|
||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button button--copy" v-clipboard="result" @click="info('HTML copied to clipboard!')">Copy</button>
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button button--copy" v-clipboard="result" @click="info('HTML复制到剪贴板!')">复制</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,23 +1,23 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Insert image">
|
||||
<modal-inner aria-label="插入图像">
|
||||
<div class="modal__content">
|
||||
<p>Please provide a <b>URL</b> for your image.</p>
|
||||
<p>请为您的图像提供<b> url </b>。</p>
|
||||
<form-entry label="URL" error="url">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="url" @keydown.enter="resolve">
|
||||
</form-entry>
|
||||
<menu-entry @click.native="openGooglePhotos(token)" v-for="token in googlePhotosTokens" :key="token.sub">
|
||||
<icon-provider slot="icon" provider-id="googlePhotos"></icon-provider>
|
||||
<div>Open from Google Photos</div>
|
||||
<div>从Google照片打开</div>
|
||||
<span>{{token.name}}</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addGooglePhotosAccount">
|
||||
<icon-provider slot="icon" provider-id="googlePhotos"></icon-provider>
|
||||
<span>Add Google Photos account</span>
|
||||
<span>添加Google Photos账号</span>
|
||||
</menu-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve">Ok</button>
|
||||
<button class="button" @click="reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Insert link">
|
||||
<modal-inner aria-label="插入链接">
|
||||
<div class="modal__content">
|
||||
<p>Please provide a <b>URL</b> for your link.</p>
|
||||
<p>请为您的链接提供<b> url </b>。</p>
|
||||
<form-entry label="URL" error="url">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="url" @keydown.enter="resolve">
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve">Ok</button>
|
||||
<button class="button" @click="reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Export with Pandoc">
|
||||
<modal-inner aria-label="使用Pandoc导出">
|
||||
<div class="modal__content">
|
||||
<p>Please choose a format for your <b>Pandoc export</b>.</p>
|
||||
<p>请为您的<b> pandoc导出</b>选择格式。</p>
|
||||
<form-entry label="Template">
|
||||
<select class="textfield" slot="field" v-model="selectedFormat" @keydown.enter="resolve()">
|
||||
<option value="asciidoc">AsciiDoc</option>
|
||||
@ -19,8 +19,8 @@
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
@ -29,7 +29,6 @@
|
||||
import FileSaver from 'file-saver';
|
||||
import networkSvc from '../../services/networkSvc';
|
||||
import editorSvc from '../../services/editorSvc';
|
||||
import googleHelper from '../../services/providers/helpers/googleHelper';
|
||||
import modalTemplate from './common/modalTemplate';
|
||||
import store from '../../store';
|
||||
import badgeSvc from '../../services/badgeSvc';
|
||||
@ -45,15 +44,11 @@ export default modalTemplate({
|
||||
const currentContent = store.getters['content/current'];
|
||||
const { selectedFormat } = this;
|
||||
store.dispatch('queue/enqueue', async () => {
|
||||
const tokenToRefresh = store.getters['workspace/sponsorToken'];
|
||||
const sponsorToken = tokenToRefresh && await googleHelper.refreshToken(tokenToRefresh);
|
||||
|
||||
try {
|
||||
const { body } = await networkSvc.request({
|
||||
method: 'POST',
|
||||
url: 'pandocExport',
|
||||
params: {
|
||||
idToken: sponsorToken && sponsorToken.idToken,
|
||||
format: selectedFormat,
|
||||
options: JSON.stringify(store.getters['data/computedSettings'].pandoc),
|
||||
metadata: JSON.stringify(currentContent.properties),
|
||||
@ -65,12 +60,8 @@ export default modalTemplate({
|
||||
FileSaver.saveAs(body, `${currentFile.name}.${selectedFormat}`);
|
||||
badgeSvc.addBadge('exportPandoc');
|
||||
} catch (err) {
|
||||
if (err.status === 401) {
|
||||
store.dispatch('modal/open', 'sponsorOnly');
|
||||
} else {
|
||||
console.error(err); // eslint-disable-line no-console
|
||||
store.dispatch('notification/error', err);
|
||||
}
|
||||
console.error(err); // eslint-disable-line no-console
|
||||
store.dispatch('notification/error', err);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -1,21 +1,21 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Export to PDF">
|
||||
<modal-inner aria-label="导出到PDF">
|
||||
<div class="modal__content">
|
||||
<p>Please choose a template for your <b>PDF export</b>.</p>
|
||||
<form-entry label="Template">
|
||||
<p>请为您的<b> pdf导出</b>选择模板。</p>
|
||||
<form-entry label="模板">
|
||||
<select class="textfield" slot="field" 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">Configure templates</a>
|
||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
@ -24,7 +24,6 @@
|
||||
import FileSaver from 'file-saver';
|
||||
import exportSvc from '../../services/exportSvc';
|
||||
import networkSvc from '../../services/networkSvc';
|
||||
import googleHelper from '../../services/providers/helpers/googleHelper';
|
||||
import modalTemplate from './common/modalTemplate';
|
||||
import store from '../../store';
|
||||
import badgeSvc from '../../services/badgeSvc';
|
||||
@ -38,24 +37,17 @@ export default modalTemplate({
|
||||
this.config.resolve();
|
||||
const currentFile = store.getters['file/current'];
|
||||
store.dispatch('queue/enqueue', async () => {
|
||||
const [sponsorToken, html] = await Promise.all([
|
||||
Promise.resolve().then(() => {
|
||||
const tokenToRefresh = store.getters['workspace/sponsorToken'];
|
||||
return tokenToRefresh && googleHelper.refreshToken(tokenToRefresh);
|
||||
}),
|
||||
exportSvc.applyTemplate(
|
||||
currentFile.id,
|
||||
this.allTemplatesById[this.selectedTemplate],
|
||||
true,
|
||||
),
|
||||
]);
|
||||
const html = await exportSvc.applyTemplate(
|
||||
currentFile.id,
|
||||
this.allTemplatesById[this.selectedTemplate],
|
||||
true,
|
||||
);
|
||||
|
||||
try {
|
||||
const { body } = await networkSvc.request({
|
||||
method: 'POST',
|
||||
url: 'pdfExport',
|
||||
params: {
|
||||
idToken: sponsorToken && sponsorToken.idToken,
|
||||
options: JSON.stringify(store.getters['data/computedSettings'].wkhtmltopdf),
|
||||
},
|
||||
body: html,
|
||||
@ -65,12 +57,8 @@ export default modalTemplate({
|
||||
FileSaver.saveAs(body, `${currentFile.name}.pdf`);
|
||||
badgeSvc.addBadge('exportPdf');
|
||||
} catch (err) {
|
||||
if (err.status === 401) {
|
||||
store.dispatch('modal/open', 'sponsorOnly');
|
||||
} else {
|
||||
console.error(err); // eslint-disable-line no-console
|
||||
store.dispatch('notification/error', err);
|
||||
}
|
||||
console.error(err); // eslint-disable-line no-console
|
||||
store.dispatch('notification/error', err);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -16,7 +16,7 @@
|
||||
{{location.description}}
|
||||
</div>
|
||||
<div class="publish-entry__buttons flex flex--row flex--center">
|
||||
<button class="publish-entry__button button" @click="remove(location)" v-title="'Remove location'">
|
||||
<button class="publish-entry__button button" @click="remove(location)" v-title="'删除位置'">
|
||||
<icon-delete></icon-delete>
|
||||
</button>
|
||||
</div>
|
||||
@ -26,10 +26,10 @@
|
||||
{{location.url}}
|
||||
</div>
|
||||
<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('Location URL copied to clipboard!')" v-title="'Copy 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>
|
||||
</button>
|
||||
<a class="publish-entry__button button" v-if="location.url" :href="location.url" target="_blank" v-title="'Open location'">
|
||||
<a class="publish-entry__button button" v-if="location.url" :href="location.url" target="_blank" v-title="'打开位置'">
|
||||
<icon-open-in-new></icon-open-in-new>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -3,19 +3,19 @@
|
||||
<div class="modal__content">
|
||||
<div class="tabs flex flex--row">
|
||||
<tab :active="tab === 'custom'" @click="tab = 'custom'">
|
||||
Custom settings
|
||||
自定义配置
|
||||
</tab>
|
||||
<tab :active="tab === 'default'" @click="tab = 'default'">
|
||||
Default settings
|
||||
默认配置
|
||||
</tab>
|
||||
</div>
|
||||
<div class="form-entry" v-if="tab === 'custom'" role="tabpanel" aria-label="Custom settings">
|
||||
<div class="form-entry" v-if="tab === 'custom'" role="tabpanel" aria-label="自定义配置">
|
||||
<label class="form-entry__label">YAML</label>
|
||||
<div class="form-entry__field form-entry__field--code-editor">
|
||||
<code-editor lang="yaml" :value="customSettings" key="custom-settings" @changed="setCustomSettings"></code-editor>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-entry" v-else-if="tab === 'default'" role="tabpanel" aria-label="Default settings">
|
||||
<div class="form-entry" v-else-if="tab === 'default'" role="tabpanel" aria-label="默认配置">
|
||||
<label class="form-entry__label">YAML</label>
|
||||
<div class="form-entry__field form-entry__field--code-editor">
|
||||
<code-editor lang="yaml" :value="defaultSettings" key="default-settings" disabled="true"></code-editor>
|
||||
@ -24,8 +24,8 @@
|
||||
<div class="modal__error modal__error--settings">{{error}}</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
@ -40,9 +40,7 @@ import defaultSettings from '../../data/defaults/defaultSettings.yml';
|
||||
import store from '../../store';
|
||||
import badgeSvc from '../../services/badgeSvc';
|
||||
|
||||
const emptySettings = `# Add your custom settings here to override the
|
||||
# default settings.
|
||||
`;
|
||||
const emptySettings = '# 增加您的自定义配置覆盖默认配置';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -10,7 +10,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -4,8 +4,8 @@
|
||||
<div class="modal__image">
|
||||
<icon-sync></icon-sync>
|
||||
</div>
|
||||
<p v-if="syncLocations.length"><b>{{currentFileName}}</b> is synchronized with the following location(s):</p>
|
||||
<p v-else><b>{{currentFileName}}</b> is not synchronized yet.</p>
|
||||
<p v-if="syncLocations.length"><b>{{currentFileName}}</b> 与以下位置同步:</p>
|
||||
<p v-else><b>{{currentFileName}}</b>尚未同步。</p>
|
||||
<div>
|
||||
<div class="sync-entry flex flex--column" v-for="location in syncLocations" :key="location.id">
|
||||
<div class="sync-entry__header flex flex--row flex--align-center">
|
||||
@ -16,20 +16,20 @@
|
||||
{{location.description}}
|
||||
</div>
|
||||
<div class="sync-entry__buttons flex flex--row flex--center">
|
||||
<button class="sync-entry__button button" @click="remove(location)" v-title="'Remove location'">
|
||||
<button class="sync-entry__button button" @click="remove(location)" v-title="'删除位置'">
|
||||
<icon-delete></icon-delete>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sync-entry__row flex flex--row flex--align-center">
|
||||
<div class="sync-entry__url">
|
||||
{{location.url || 'Google Drive app data'}}
|
||||
{{location.url || 'Gitee app data'}}
|
||||
</div>
|
||||
<div class="sync-entry__buttons flex flex--row flex--center" v-if="location.url">
|
||||
<button class="sync-entry__button button" v-clipboard="location.url" @click="info('Location URL copied to clipboard!')" v-title="'Copy URL'">
|
||||
<button class="sync-entry__button button" v-clipboard="location.url" @click="info('位置URL复制到剪贴板!')" v-title="'复制URL'">
|
||||
<icon-content-copy></icon-content-copy>
|
||||
</button>
|
||||
<a class="sync-entry__button button" v-if="location.url" :href="location.url" target="_blank" v-title="'Open location'">
|
||||
<a class="sync-entry__button button" v-if="location.url" :href="location.url" target="_blank" v-title="'打开位置'">
|
||||
<icon-open-in-new></icon-open-in-new>
|
||||
</a>
|
||||
</div>
|
||||
@ -37,11 +37,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__info" v-if="syncLocations.length">
|
||||
<b>Tip:</b> Removing a location won't delete any file.
|
||||
<b>提示:</b> 删除位置不会删除任何文件。
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button button--resolve" @click="config.resolve()">Close</button>
|
||||
<button class="button button--resolve" @click="config.resolve()">关闭</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<modal-inner class="modal__inner-1--templates" aria-label="Manage templates">
|
||||
<modal-inner class="modal__inner-1--templates" aria-label="管理模板">
|
||||
<div class="modal__content">
|
||||
<div class="form-entry">
|
||||
<label class="form-entry__label" for="template">Template</label>
|
||||
<label class="form-entry__label" for="template">模板</label>
|
||||
<div class="form-entry__field">
|
||||
<input v-if="isEditing" id="template" type="text" class="textfield" v-focus @blur="submitEdit()" @keydown.enter="submitEdit()" @keydown.esc.stop="submitEdit(true)" v-model="editingName">
|
||||
<select v-else id="template" v-model="selectedId" class="textfield">
|
||||
@ -12,31 +12,31 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-entry__actions flex flex--row flex--end">
|
||||
<button class="form-entry__button button" @click="create" v-title="'New template'">
|
||||
<button class="form-entry__button button" @click="create" v-title="'新建模板'">
|
||||
<icon-file-plus></icon-file-plus>
|
||||
</button>
|
||||
<button class="form-entry__button button" @click="copy" v-title="'Copy template'">
|
||||
<button class="form-entry__button button" @click="copy" v-title="'复制模板'">
|
||||
<icon-file-multiple></icon-file-multiple>
|
||||
</button>
|
||||
<button v-if="!isReadOnly" class="form-entry__button button" @click="isEditing = true" v-title="'Rename template'">
|
||||
<button v-if="!isReadOnly" class="form-entry__button button" @click="isEditing = true" v-title="'重命名模板'">
|
||||
<icon-pen></icon-pen>
|
||||
</button>
|
||||
<button v-if="!isReadOnly" class="form-entry__button button" @click="remove" v-title="'Remove template'">
|
||||
<button v-if="!isReadOnly" class="form-entry__button button" @click="remove" v-title="'删除模板'">
|
||||
<icon-delete></icon-delete>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-entry">
|
||||
<label class="form-entry__label">Value</label>
|
||||
<label class="form-entry__label">值</label>
|
||||
<div class="form-entry__field" v-for="(template, id) in templates" :key="id" v-if="id === selectedId">
|
||||
<code-editor lang="handlebars" :value="template.value" :disabled="isReadOnly" @changed="template.value = $event"></code-editor>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!isReadOnly">
|
||||
<a href="javascript:void(0)" v-if="!showHelpers" @click="showHelpers = true">Add helpers</a>
|
||||
<a href="javascript:void(0)" v-if="!showHelpers" @click="showHelpers = true">添加帮助</a>
|
||||
<div class="form-entry" v-else>
|
||||
<br>
|
||||
<label class="form-entry__label">Helpers</label>
|
||||
<label class="form-entry__label">帮助</label>
|
||||
<div class="form-entry__field" v-for="(template, id) in templates" :key="id" v-if="id === selectedId">
|
||||
<code-editor lang="javascript" :value="template.helpers" @changed="template.helpers = $event"></code-editor>
|
||||
</div>
|
||||
@ -44,8 +44,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<modal-inner class="modal__inner-1--workspace-management" aria-label="Manage workspaces">
|
||||
<modal-inner class="modal__inner-1--workspace-management" aria-label="管理文档空间">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-database></icon-database>
|
||||
</div>
|
||||
<p><br>可以访问以下工作区:</p>
|
||||
<p><br>可以访问以下文档空间:</p>
|
||||
<div class="workspace-entry flex flex--column" v-for="(workspace, id) in workspacesById" :key="id">
|
||||
<div class="flex flex--column">
|
||||
<div class="workspace-entry__header flex flex--row flex--align-center">
|
||||
@ -27,10 +27,10 @@
|
||||
{{workspace.url}}
|
||||
</div>
|
||||
<div class="workspace-entry__buttons flex flex--row">
|
||||
<button class="workspace-entry__button button" v-clipboard="workspace.url" @click="info('工作区URL已复制到剪贴板!')" v-title="'复制URL'">
|
||||
<button class="workspace-entry__button button" v-clipboard="workspace.url" @click="info('文档空间URL已复制到剪贴板!')" v-title="'复制URL'">
|
||||
<icon-content-copy></icon-content-copy>
|
||||
</button>
|
||||
<a class="workspace-entry__button button" :href="workspace.url" target="_blank" v-title="'打开工作区'">
|
||||
<a class="workspace-entry__button button" :href="workspace.url" target="_blank" v-title="'打开文档空间'">
|
||||
<icon-open-in-new></icon-open-in-new>
|
||||
</a>
|
||||
</div>
|
||||
@ -40,10 +40,10 @@
|
||||
{{workspace.locationUrl}}
|
||||
</div>
|
||||
<div class="workspace-entry__buttons flex flex--row">
|
||||
<button class="workspace-entry__button button" v-clipboard="workspace.locationUrl" @click="info('工作区URL已复制到剪贴板!')" v-title="'复制URL'">
|
||||
<button class="workspace-entry__button button" v-clipboard="workspace.locationUrl" @click="info('文档空间URL已复制到剪贴板!')" v-title="'复制URL'">
|
||||
<icon-content-copy></icon-content-copy>
|
||||
</button>
|
||||
<a class="workspace-entry__button button" :href="workspace.locationUrl" target="_blank" v-title="'打开工作区位置'">
|
||||
<a class="workspace-entry__button button" :href="workspace.locationUrl" target="_blank" v-title="'打开文档空间位置'">
|
||||
<icon-open-in-new></icon-open-in-new>
|
||||
</a>
|
||||
</div>
|
||||
@ -117,9 +117,9 @@ export default {
|
||||
},
|
||||
async remove(id) {
|
||||
if (id === this.mainWorkspace.id) {
|
||||
this.info('您的主工作区无法删除。');
|
||||
this.info('您的主文档空间无法删除。');
|
||||
} else if (id === this.currentWorkspace.id) {
|
||||
this.info('请先关闭工作区,然后再将其删除。');
|
||||
this.info('请先关闭文档空间,然后再将其删除。');
|
||||
} else {
|
||||
try {
|
||||
await store.dispatch('modal/open', 'removeWorkspace');
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="modal__inner-1" role="dialog">
|
||||
<div class="modal__inner-2">
|
||||
<button class="modal__close-button button not-tabbable" @click="config.reject()" v-title="'Close modal'">
|
||||
<button class="modal__close-button button not-tabbable" @click="config.reject()" v-title="'关闭窗口'">
|
||||
<icon-close></icon-close>
|
||||
</button>
|
||||
<slot></slot>
|
||||
|
@ -1,36 +1,36 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Publish to Blogger Page">
|
||||
<modal-inner aria-label="发布到Blogger Page">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="bloggerPage"></icon-provider>
|
||||
</div>
|
||||
<p>Publish <b>{{currentFileName}}</b> to your <b>Blogger Page</b>.</p>
|
||||
<p>发布<b> {{CurrentFileName}} </b>到您的<b> Blogger页面</b>。</p>
|
||||
<form-entry label="Blog URL" error="blogUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="blogUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> http://example.blogger.com/
|
||||
<b>例如:</b> http://example.blogger.com/
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Existing page ID" info="optional">
|
||||
<form-entry label="现有页面ID" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="pageId" @keydown.enter="resolve()">
|
||||
</form-entry>
|
||||
<form-entry label="Template">
|
||||
<form-entry label="模板">
|
||||
<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">Configure templates</a>
|
||||
<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>.
|
||||
<b>提示:</b> 您可以在<a href="javascript:void(0)" @click="openFileProperties">文件属性</a>中提供<code>title</code>的值
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,37 +1,37 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Publish to Blogger">
|
||||
<modal-inner aria-label="发布到Blogger">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="blogger"></icon-provider>
|
||||
</div>
|
||||
<p>Publish <b>{{currentFileName}}</b> to your <b>Blogger</b> site.</p>
|
||||
<p>向您的<b> Blogger </b>网站发布<b> {{CurrentFileName}} </b>。</p>
|
||||
<form-entry label="Blog URL" error="blogUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="blogUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> http://example.blogger.com/
|
||||
<b>例如:</b> http://example.blogger.com/
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Existing post ID" info="optional">
|
||||
<form-entry label="现有的帖子ID" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="postId" @keydown.enter="resolve()">
|
||||
</form-entry>
|
||||
<form-entry label="Template">
|
||||
<form-entry label="模板">
|
||||
<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">Configure templates</a>
|
||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
<div class="modal__info">
|
||||
<b>ProTip:</b> You can provide values for <code>title</code>, <code>tags</code>,
|
||||
<code>status</code> and <code>date</code> in the <a href="javascript:void(0)" @click="openFileProperties">file properties</a>.
|
||||
<b>提示:</b> 在<a href="javascript:void(0)" @click="openFileProperties">文件中</a>中您可以为 <code>title</code>, <code>tags</code>,
|
||||
<code>status</code> 和 <code>date</code>提供值。
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,20 +1,20 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Insert image">
|
||||
<modal-inner aria-label="插入图片">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="couchdb"></icon-provider>
|
||||
</div>
|
||||
<p>Please provide your credentials to login to <b>CouchDB</b>.</p>
|
||||
<form-entry label="Name" error="name">
|
||||
<p>请提供您的凭据,以登录<b>CouchDB</b>。</p>
|
||||
<form-entry label="用户名" error="name">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="name" @keydown.enter="resolve()">
|
||||
</form-entry>
|
||||
<form-entry label="Password" error="password">
|
||||
<form-entry label="密码" error="password">
|
||||
<input slot="field" class="textfield" type="password" v-model.trim="password" @keydown.enter="resolve()">
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Add CouchDB workspace">
|
||||
<modal-inner aria-label="增加CouchDB文档空间">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="couchdb"></icon-provider>
|
||||
</div>
|
||||
<p>Create a workspace synced with a <b>CouchDB</b> database.</p>
|
||||
<p>创建一个与<b>CouchDB</b>数据库同步的文档空间。</p>
|
||||
<form-entry label="Database URL" error="dbUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="dbUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://instance.smileupps.com/stackedit-workspace
|
||||
<b>例如:</b> https://instance.smileupps.com/stackedit-workspace
|
||||
</div>
|
||||
<div class="form-entry__actions">
|
||||
<!-- https://community.stackedit.io/t/couchdb-workspace-setup/ -->
|
||||
<a href="#" target="_blank">How to setup?</a>
|
||||
<a href="#" target="_blank">如何设置?</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Link Dropbox account">
|
||||
<modal-inner aria-label="链接Dropbox账号">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="dropbox"></icon-provider>
|
||||
</div>
|
||||
<p>Link your <b>Dropbox</b> account to <b>StackEdit</b>.</p>
|
||||
<p>将您的<b>Dropbox</b>链接到<b>StackEdit</b>。</p>
|
||||
<div class="form-entry">
|
||||
<div class="form-entry__checkbox">
|
||||
<label>
|
||||
<input type="checkbox" v-model="restrictedAccess"> Restrict access
|
||||
<input type="checkbox" v-model="restrictedAccess"> 限制访问
|
||||
</label>
|
||||
<div class="form-entry__info">
|
||||
If checked, access will be restricted to the <b>/Applications/StackEdit (restricted)</b> folder.
|
||||
如果限制,访问将仅限于<b>/Applications/StackEdit (restricted)</b>文件夹。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="config.resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="config.resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Publish to Dropbox">
|
||||
<modal-inner aria-label="发布到Dropbox">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="dropbox"></icon-provider>
|
||||
</div>
|
||||
<p>Publish <b>{{currentFileName}}</b> to your <b>Dropbox</b>.</p>
|
||||
<p>发布到您的<b>Dropbox</b>。</p>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.fullAccess ? '' : '/Applications/StackEdit (restricted)'}}/path/to/My Document.html<br>
|
||||
If the file exists, it will be overwritten.
|
||||
<b>例如:</b> {{config.token.fullAccess ? '' : '/Applications/StackEdit (restricted)'}}/path/to/My Document.html<br>
|
||||
如果文件存在,将被覆盖。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Template">
|
||||
@ -19,13 +19,13 @@
|
||||
</option>
|
||||
</select>
|
||||
<div class="form-entry__actions">
|
||||
<a href="javascript:void(0)" @click="configureTemplates">Configure templates</a>
|
||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,21 +1,21 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with Dropbox">
|
||||
<modal-inner aria-label="与 Dropbox 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="dropbox"></icon-provider>
|
||||
</div>
|
||||
<p>Save <b>{{currentFileName}}</b> to your <b>Dropbox</b> and keep it synced.</p>
|
||||
<p>将<b> {{CurrentFileName}} </b>保存到您的<b>Dropbox</b>并保持同步。</p>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.fullAccess ? '' : '/Applications/StackEdit (restricted)'}}/path/to/My Document.md<br>
|
||||
If the file exists, it will be overwritten.
|
||||
<b>例如:</b> {{config.token.fullAccess ? '' : '/Applications/StackEdit (restricted)'}}/path/to/My Document.md<br>
|
||||
如果文件存在,将被覆盖。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Publish to Gist">
|
||||
<modal-inner aria-label="发布到Gist">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gist"></icon-provider>
|
||||
</div>
|
||||
<p>Publish <b>{{currentFileName}}</b> to a <b>Gist</b>.</p>
|
||||
<p>发布<b> {{CurrentFileName}} </b>到<b>Gist</b>。</p>
|
||||
<form-entry label="Filename" 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"> Public
|
||||
<input type="checkbox" v-model="isPublic"> 公开的
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<form-entry label="Existing Gist ID" info="optional">
|
||||
<form-entry label="Existing Gist ID" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If the file exists in the Gist, it will be overwritten.
|
||||
如果文件存在于Gist中,则将被覆盖。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Template">
|
||||
@ -28,7 +28,7 @@
|
||||
</option>
|
||||
</select>
|
||||
<div class="form-entry__actions">
|
||||
<a href="javascript:void(0)" @click="configureTemplates">Configure templates</a>
|
||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
<div class="modal__info">
|
||||
@ -36,8 +36,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,30 +1,30 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with Gist">
|
||||
<modal-inner aria-label="与 Gist 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gist"></icon-provider>
|
||||
</div>
|
||||
<p>Save <b>{{currentFileName}}</b> to a <b>Gist</b> and keep it synced.</p>
|
||||
<p>将<b> {{currentFileName}} </b>保存到<b>Gist</b>并保持同步。</p>
|
||||
<form-entry label="Filename" 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"> Public
|
||||
<input type="checkbox" v-model="isPublic"> 公开的
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<form-entry label="Existing Gist ID" info="optional">
|
||||
<form-entry label="Existing Gist ID" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="gistId" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If the file exists in the Gist, it will be overwritten.
|
||||
如果文件存在于Gist中,则将被覆盖。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Gitea account">
|
||||
<modal-inner aria-label="Gitea账号">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitea"></icon-provider>
|
||||
</div>
|
||||
<p>Link your <b>Gitea</b> account to <b>StackEdit</b>.</p>
|
||||
<p>将您的<b>Gitea</b>链接到<b>StackEdit</b>。</p>
|
||||
<form-entry label="Gitea URL" error="serverUrl">
|
||||
<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()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://gitea.example.com/
|
||||
<b>例如:</b> https://gitea.example.com/
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Application ID" error="applicationId">
|
||||
@ -18,16 +18,16 @@
|
||||
<form-entry label="Application Secret" error="applicationSecret">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="applicationSecret" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
You have to configure an OAuth2 Application with redirect URL <b>{{redirectUrl}}</b>
|
||||
您必须使用重定向url <b>{{redirectUrl}}</b>配置OAuth2应用程序
|
||||
</div>
|
||||
<div class="form-entry__actions">
|
||||
<a href="https://docs.gitea.io/en-us/oauth2-provider/" target="_blank">More info</a>
|
||||
<a href="https://docs.gitea.io/en-us/oauth2-provider/" target="_blank">更多信息</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,32 +1,32 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with Gitea">
|
||||
<modal-inner aria-label="与 Gitea 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitea"></icon-provider>
|
||||
</div>
|
||||
<p>Open a file from your <b>Gitea</b> project and keep it synced.</p>
|
||||
<p>从您的<b>Gitea</b>项目中打开文件,并保持同步。</p>
|
||||
<form-entry label="Project URL" error="projectUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.serverUrl}}/path/to/project
|
||||
<b>例如:</b> {{ config.token.serverUrl }}/path/to/project
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md
|
||||
<b>例如:</b> path/to/README.md
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,27 +1,27 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Publish to Gitea">
|
||||
<modal-inner aria-label="发布到Gitea">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitea"></icon-provider>
|
||||
</div>
|
||||
<p>Publish <b>{{currentFileName}}</b> to your <b>Gitea</b> project.</p>
|
||||
<p>向您的<b> Gitea </b>项目发布<b> {{CurrentFileName}} </b>。</p>
|
||||
<form-entry label="Project URL" error="projectUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.serverUrl}}/path/to/project
|
||||
<b>例如:</b> {{config.token.serverUrl}}/path/to/project
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md<br>
|
||||
If the file exists, it will be overwritten.
|
||||
<b>例如:</b> path/to/README.md<br>
|
||||
如果文件存在,将被覆盖。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Template">
|
||||
@ -31,13 +31,13 @@
|
||||
</option>
|
||||
</select>
|
||||
<div class="form-entry__actions">
|
||||
<a href="javascript:void(0)" @click="configureTemplates">Configure templates</a>
|
||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,33 +1,33 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with Gitea">
|
||||
<modal-inner aria-label="与 Gitea 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitea"></icon-provider>
|
||||
</div>
|
||||
<p>Save <b>{{currentFileName}}</b> to your <b>Gitea</b> project and keep it synced.</p>
|
||||
<p>将<b> {{currentFileName}} </b>保存到<b> Gitea </b>项目,并保持同步。</p>
|
||||
<form-entry label="Project URL" error="projectUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.serverUrl}}/path/to/project
|
||||
<b>例如:</b> {{config.token.serverUrl}}/path/to/project
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md<br>
|
||||
If the file exists, it will be overwritten.
|
||||
<b>例如:</b> path/to/README.md<br>
|
||||
如果文件存在,将被覆盖。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,32 +1,32 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with Gitea">
|
||||
<modal-inner aria-label="与 Gitea 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitea"></icon-provider>
|
||||
</div>
|
||||
<p>Create a workspace synced with a <b>Gitea</b> project folder.</p>
|
||||
<p>创建一个与<b> Gitea </b>项目文件夹同步的文档空间。</p>
|
||||
<form-entry label="Project URL" error="projectUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.serverUrl}}/path/to/project
|
||||
<b>例如:</b> {{config.token.serverUrl}}/path/to/project
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Folder path" info="optional">
|
||||
<form-entry label="文件夹路径" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the root folder will be used.
|
||||
如果不提供,将使用根文件夹。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,21 +1,21 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Link Gitee account">
|
||||
<modal-inner aria-label="链接Gitee账号">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitee"></icon-provider>
|
||||
</div>
|
||||
<p>Link your <b>Gitee</b> account to <b>StackEdit</b>.</p>
|
||||
<p>将您的<b>Gitee</b>账号链接到<b>StackEdit</b>。</p>
|
||||
<div class="form-entry">
|
||||
<div class="form-entry__checkbox">
|
||||
<label>
|
||||
<input type="checkbox" v-model="repoFullAccess"> Grant access to your private repositories
|
||||
<input type="checkbox" v-model="repoFullAccess"> 授予您私人仓库的访问权限
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="config.resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="config.resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,32 +1,32 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with Gitee">
|
||||
<modal-inner aria-label="与 Gitee 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitee"></icon-provider>
|
||||
</div>
|
||||
<p>Open a file from your <b>Gitee</b> repository and keep it synced.</p>
|
||||
<form-entry label="Repository URL" error="repoUrl">
|
||||
<p>从您的<b> Gitee </b>仓库中打开文件,并保持同步。</p>
|
||||
<form-entry label="仓库URL" error="repoUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="repoUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://gitee.com/owner/my-repo
|
||||
<b>例如:</b> https://gitee.com/owner/my-repo
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md
|
||||
<b>例如:</b> path/to/README.md
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,27 +1,27 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Publish to Gitee">
|
||||
<modal-inner aria-label="发布到Gitee">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitee"></icon-provider>
|
||||
</div>
|
||||
<p>Publish <b>{{currentFileName}}</b> to your <b>Gitee</b> repository.</p>
|
||||
<form-entry label="Repository URL" error="repoUrl">
|
||||
<form-entry label="仓库URL" error="repoUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="repoUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://gitee.com/owner/my-repo
|
||||
<b>例如:</b> https://gitee.com/owner/my-repo
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md<br>
|
||||
If the file exists, it will be overwritten.
|
||||
<b>例如:</b> path/to/README.md<br>
|
||||
如果文件存在,将被覆盖。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Template">
|
||||
@ -31,13 +31,13 @@
|
||||
</option>
|
||||
</select>
|
||||
<div class="form-entry__actions">
|
||||
<a href="javascript:void(0)" @click="configureTemplates">Configure templates</a>
|
||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,33 +1,33 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with Gitee">
|
||||
<modal-inner aria-label="与 Gitee 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitee"></icon-provider>
|
||||
</div>
|
||||
<p>Save <b>{{currentFileName}}</b> to your <b>Gitee</b> repository and keep it synced.</p>
|
||||
<form-entry label="Repository URL" error="repoUrl">
|
||||
<form-entry label="仓库URL" error="repoUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="repoUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://gitee.com/owner/my-repo
|
||||
<b>例如:</b> https://gitee.com/owner/my-repo
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md<br>
|
||||
If the file exists, it will be overwritten.
|
||||
<b>例如:</b> path/to/README.md<br>
|
||||
如果文件存在,将被覆盖。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,32 +1,32 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with Gitee">
|
||||
<modal-inner aria-label="与 Gitee 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitee"></icon-provider>
|
||||
</div>
|
||||
<p>Create a workspace synced with a <b>Gitee</b> repository folder.</p>
|
||||
<form-entry label="Repository URL" error="repoUrl">
|
||||
<p>创建一个与<b>Gitee</b>仓库文件夹同步的文档空间。</p>
|
||||
<form-entry label="仓库URL" error="repoUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="repoUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://gitee.com/owner/my-repo
|
||||
<b>例如:</b> https://gitee.com/owner/my-repo
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Folder path" info="optional">
|
||||
<form-entry label="文件夹路径" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the root folder will be used.
|
||||
如果不提供,将使用根文件夹。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,21 +1,21 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Link GitHub account">
|
||||
<modal-inner aria-label="链接GitHub账号">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="github"></icon-provider>
|
||||
</div>
|
||||
<p>Link your <b>GitHub</b> account to <b>StackEdit</b>.</p>
|
||||
<p>将您的<b>Github账号</b>链接到<b>StackEdit</b>。</p>
|
||||
<div class="form-entry">
|
||||
<div class="form-entry__checkbox">
|
||||
<label>
|
||||
<input type="checkbox" v-model="repoFullAccess"> Grant access to your private repositories
|
||||
<input type="checkbox" v-model="repoFullAccess"> 授予您私人仓库的访问权限
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="config.resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="config.resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,32 +1,32 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with GitHub">
|
||||
<modal-inner aria-label="与 GitHub 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="github"></icon-provider>
|
||||
</div>
|
||||
<p>Open a file from your <b>GitHub</b> repository and keep it synced.</p>
|
||||
<form-entry label="Repository URL" error="repoUrl">
|
||||
<p>从您的<b>GitHub</b> repository and keep it synced.</p>
|
||||
<form-entry label="仓库URL" error="repoUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="repoUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://github.com/owner/my-repo
|
||||
<b>例如:</b> https://github.com/owner/my-repo
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md
|
||||
<b>例如:</b> path/to/README.md
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,27 +1,27 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Publish to GitHub">
|
||||
<modal-inner aria-label="发布到GitHub">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="github"></icon-provider>
|
||||
</div>
|
||||
<p>Publish <b>{{currentFileName}}</b> to your <b>GitHub</b> repository.</p>
|
||||
<form-entry label="Repository URL" error="repoUrl">
|
||||
<form-entry label="仓库URL" error="repoUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="repoUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://github.com/owner/my-repo
|
||||
<b>例如:</b> https://github.com/owner/my-repo
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md<br>
|
||||
If the file exists, it will be overwritten.
|
||||
<b>例如:</b> path/to/README.md<br>
|
||||
如果文件存在,将被覆盖。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Template">
|
||||
@ -31,13 +31,13 @@
|
||||
</option>
|
||||
</select>
|
||||
<div class="form-entry__actions">
|
||||
<a href="javascript:void(0)" @click="configureTemplates">Configure templates</a>
|
||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,33 +1,33 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with GitHub">
|
||||
<modal-inner aria-label="与 GitHub 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="github"></icon-provider>
|
||||
</div>
|
||||
<p>Save <b>{{currentFileName}}</b> to your <b>GitHub</b> repository and keep it synced.</p>
|
||||
<form-entry label="Repository URL" error="repoUrl">
|
||||
<form-entry label="仓库URL" error="repoUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="repoUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://github.com/owner/my-repo
|
||||
<b>例如:</b> https://github.com/owner/my-repo
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md<br>
|
||||
If the file exists, it will be overwritten.
|
||||
<b>例如:</b> path/to/README.md<br>
|
||||
如果文件存在,将被覆盖。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,32 +1,32 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with GitHub">
|
||||
<modal-inner aria-label="与 GitHub 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="github"></icon-provider>
|
||||
</div>
|
||||
<p>Create a workspace synced with a <b>GitHub</b> repository folder.</p>
|
||||
<form-entry label="Repository URL" error="repoUrl">
|
||||
<p>创建一个与<b>GitHub</b>仓库文件夹同步的文档空间。</p>
|
||||
<form-entry label="仓库URL" error="repoUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="repoUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://github.com/owner/my-repo
|
||||
<b>例如:</b> https://github.com/owner/my-repo
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Folder path" info="optional">
|
||||
<form-entry label="文件夹路径" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the root folder will be used.
|
||||
如果不提供,将使用根文件夹。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,30 +1,30 @@
|
||||
<template>
|
||||
<modal-inner aria-label="GitLab account">
|
||||
<modal-inner aria-label="GitLab账号">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitlab"></icon-provider>
|
||||
</div>
|
||||
<p>Link your <b>GitLab</b> account to <b>StackEdit</b>.</p>
|
||||
<p>将您的<b>GitLab</b>链接到<b>StackEdit</b>。</p>
|
||||
<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-else slot="field" class="textfield" type="text" v-model.trim="serverUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://gitlab.example.com/
|
||||
<b>例如:</b> https://gitlab.example.com/
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Application ID" error="applicationId">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="applicationId" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
You have to configure an OAuth2 Application with redirect URL <b>{{redirectUrl}}</b>
|
||||
您必须使用重定向url <b>{{redirectUrl}}</b>配置OAuth2应用程序
|
||||
</div>
|
||||
<div class="form-entry__actions">
|
||||
<a href="https://docs.gitlab.com/ee/integration/oauth_provider.html" target="_blank">More info</a>
|
||||
<a href="https://docs.gitlab.com/ee/integration/oauth_provider.html" target="_blank">更多信息</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,32 +1,32 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with GitLab">
|
||||
<modal-inner aria-label="与 GitLab 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitlab"></icon-provider>
|
||||
</div>
|
||||
<p>Open a file from your <b>GitLab</b> project and keep it synced.</p>
|
||||
<p>从您的<b>GitLab</b>项目中打开文件,并保持同步。</p>
|
||||
<form-entry label="Project URL" error="projectUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.serverUrl}}/path/to/project
|
||||
<b>例如:</b> {{config.token.serverUrl}}/path/to/project
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md
|
||||
<b>例如:</b> path/to/README.md
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Publish to GitLab">
|
||||
<modal-inner aria-label="发布到GitLab">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitlab"></icon-provider>
|
||||
@ -8,20 +8,20 @@
|
||||
<form-entry label="Project URL" error="projectUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.serverUrl}}/path/to/project
|
||||
<b>例如:</b> {{config.token.serverUrl}}/path/to/project
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md<br>
|
||||
If the file exists, it will be overwritten.
|
||||
<b>例如:</b> path/to/README.md<br>
|
||||
如果文件存在,将被覆盖。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Template">
|
||||
@ -31,13 +31,13 @@
|
||||
</option>
|
||||
</select>
|
||||
<div class="form-entry__actions">
|
||||
<a href="javascript:void(0)" @click="configureTemplates">Configure templates</a>
|
||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,33 +1,33 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with GitLab">
|
||||
<modal-inner aria-label="与 GitLab 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitlab"></icon-provider>
|
||||
</div>
|
||||
<p>Save <b>{{currentFileName}}</b> to your <b>GitLab</b> project and keep it synced.</p>
|
||||
<p>Save <b>{{currentFileName}}</b> to your <b>GitLab</b>项目中打开文件,并保持同步。</p>
|
||||
<form-entry label="Project URL" error="projectUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.serverUrl}}/path/to/project
|
||||
<b>例如:</b> {{config.token.serverUrl}}/path/to/project
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="File path" error="path">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> path/to/README.md<br>
|
||||
If the file exists, it will be overwritten.
|
||||
<b>例如:</b> path/to/README.md<br>
|
||||
如果文件存在,将被覆盖。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,32 +1,32 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with GitLab">
|
||||
<modal-inner aria-label="与 GitLab 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="gitlab"></icon-provider>
|
||||
</div>
|
||||
<p>Create a workspace synced with a <b>GitLab</b> project folder.</p>
|
||||
<p>创建一个与<b>GitLab</b>仓库文件夹同步的文档空间。</p>
|
||||
<form-entry label="Project URL" error="projectUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="projectUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> {{config.token.serverUrl}}/path/to/project
|
||||
<b>例如:</b> {{config.token.serverUrl}}/path/to/project
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Folder path" info="optional">
|
||||
<form-entry label="文件夹路径" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="path" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the root folder will be used.
|
||||
如果不提供,将使用根文件夹。
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Branch" info="optional">
|
||||
<form-entry label="分支" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="branch" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the <code>master</code> branch will be used.
|
||||
如果未提供,将使用<code> master </code>分支。
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Link Google Drive account">
|
||||
<modal-inner aria-label="链接Google Drive账号">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="googleDrive"></icon-provider>
|
||||
</div>
|
||||
<p>Link your <b>Google Drive</b> account to <b>StackEdit</b>.</p>
|
||||
<p>将您的<b>Google Drive</b>链接到<b>StackEdit</b>。</p>
|
||||
<div class="form-entry">
|
||||
<div class="form-entry__checkbox">
|
||||
<label>
|
||||
<input type="checkbox" v-model="restrictedAccess"> Restrict access
|
||||
<input type="checkbox" v-model="restrictedAccess"> 限制访问
|
||||
</label>
|
||||
<div class="form-entry__info">
|
||||
If checked, access will be restricted to files that you have opened or created with <b>StackEdit</b>.
|
||||
如果限制,则将访问仅限于您使用<b>StackEdit</b>创建的文件。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="config.resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="config.resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Publish to Google Drive">
|
||||
<modal-inner aria-label="发布到Google Drive">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="googleDrive"></icon-provider>
|
||||
</div>
|
||||
<p>Publish <b>{{currentFileName}}</b> to your <b>Google Drive</b> account.</p>
|
||||
<form-entry label="Folder ID" info="optional">
|
||||
<form-entry label="Folder ID" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="folderId" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the file will be created in your Drive root folder.
|
||||
@ -14,7 +14,7 @@
|
||||
<a href="javascript:void(0)" @click="openFolder">Choose folder</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Existing file ID" info="optional">
|
||||
<form-entry label="Existing file ID" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="fileId" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
This will overwrite the file on the server.
|
||||
@ -39,7 +39,7 @@
|
||||
</option>
|
||||
</select>
|
||||
<div class="form-entry__actions">
|
||||
<a href="javascript:void(0)" @click="configureTemplates">Configure templates</a>
|
||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
<div class="modal__info">
|
||||
@ -47,8 +47,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Synchronize with Google Drive">
|
||||
<modal-inner aria-label="与 Google Drive 同步">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="googleDrive"></icon-provider>
|
||||
</div>
|
||||
<p>Save <b>{{currentFileName}}</b> to your <b>Google Drive</b> account and keep it synced.</p>
|
||||
<form-entry label="Folder ID" info="optional">
|
||||
<form-entry label="Folder ID" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="folderId" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, the file will be created in your Drive root folder.
|
||||
@ -14,7 +14,7 @@
|
||||
<a href="javascript:void(0)" @click="openFolder">Choose folder</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Existing file ID" info="optional">
|
||||
<form-entry label="Existing file ID" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="fileId" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
This will overwrite the file on the server.
|
||||
@ -22,8 +22,8 @@
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,23 +1,23 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Add Google Drive workspace">
|
||||
<modal-inner aria-label="添加Google Drive文档空间">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="googleDrive"></icon-provider>
|
||||
</div>
|
||||
<p>Create a workspace synced with a <b>Google Drive</b> folder.</p>
|
||||
<form-entry label="Folder ID" info="optional">
|
||||
<p>创建一个与<b> Google Drive </b>文件夹同步的文档空间。</p>
|
||||
<form-entry label="Folder ID" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="folderId" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
If not supplied, a new workspace folder will be created in your Drive root folder.
|
||||
如果不提供,将在驱动器根文件夹中创建一个新的Workspace文件夹。
|
||||
</div>
|
||||
<div class="form-entry__actions">
|
||||
<a href="javascript:void(0)" @click="openFolder">Choose folder</a>
|
||||
<a href="javascript:void(0)" @click="openFolder">选择文件夹</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<modal-inner class="modal__inner-1--google-photo" aria-label="Import Google Photo">
|
||||
<modal-inner class="modal__inner-1--google-photo" aria-label="导入Google照片">
|
||||
<div class="modal__content">
|
||||
<div class="google-photo__tumbnail" :style="{backgroundImage: thumbnailUrl}"></div>
|
||||
<form-entry label="Title" info="optional">
|
||||
<form-entry label="标题" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="title" @keydown.enter="resolve()">
|
||||
</form-entry>
|
||||
<form-entry label="Size limit" info="optional">
|
||||
<form-entry label="尺寸限制" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="size" @keydown.enter="resolve()">
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,39 +1,39 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Publish to WordPress">
|
||||
<modal-inner aria-label="发布到WordPress">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="wordpress"></icon-provider>
|
||||
</div>
|
||||
<p>Publish <b>{{currentFileName}}</b> to your <b>WordPress</b> site.</p>
|
||||
<form-entry label="Site domain" error="domain">
|
||||
<form-entry label="站点域名" error="domain">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="domain" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> example.wordpress.com<br>
|
||||
<b>例如:</b> example.wordpress.com<br>
|
||||
<b>Note:</b> Jetpack is required for self-hosted sites.
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Existing post ID" info="optional">
|
||||
<form-entry label="现有的帖子ID" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="postId" @keydown.enter="resolve()">
|
||||
</form-entry>
|
||||
<form-entry label="Template">
|
||||
<form-entry label="模板">
|
||||
<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">Configure templates</a>
|
||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
<div class="modal__info">
|
||||
<b>ProTip:</b> You can provide values for <code>title</code>, <code>tags</code>,
|
||||
<b>提示:</b> 在<a href="javascript:void(0)" @click="openFileProperties">文件属性</a>中您可以为 <code>title</code>, <code>tags</code>,
|
||||
<code>categories</code>, <code>excerpt</code>, <code>author</code>, <code>featuredImage</code>,
|
||||
<code>status</code> and <code>date</code> in the <a href="javascript:void(0)" @click="openFileProperties">file properties</a>.
|
||||
<code>status</code> 和 <code>date</code>提供值。
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,29 +1,29 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Link Zendesk account">
|
||||
<modal-inner aria-label="链接Zendesk账号">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="zendesk"></icon-provider>
|
||||
</div>
|
||||
<p>Link your <b>Zendesk</b> account to <b>StackEdit</b>.</p>
|
||||
<p>将您的<b>Zendesk</b>链接到<b>StackEdit</b>。</p>
|
||||
<form-entry label="Site URL" error="siteUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="siteUrl" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://example.zendesk.com/
|
||||
<b>例如:</b> https://example.zendesk.com/
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Client Unique Identifier" error="clientId">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="clientId" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
You have to configure an OAuth Client with redirect URL <b>{{redirectUrl}}</b>
|
||||
您必须使用重定向url <b>{{redirectUrl}}</b>配置OAuth客户端
|
||||
</div>
|
||||
<div class="form-entry__actions">
|
||||
<a href="https://support.zendesk.com/hc/en-us/articles/203663836" target="_blank">More info</a>
|
||||
<a href="https://support.zendesk.com/hc/en-us/articles/203663836" target="_blank">更多信息</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -1,43 +1,43 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Publish to Zendesk">
|
||||
<modal-inner aria-label="发布到Zendesk">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="zendesk"></icon-provider>
|
||||
</div>
|
||||
<p>Publish <b>{{currentFileName}}</b> to your <b>Zendesk Help Center</b>.</p>
|
||||
<p>向您的<b>Zendesk帮助中心</b>发布<b> {{CurrentFileName}} </b>。</p>
|
||||
<form-entry label="Section ID" error="sectionId">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="sectionId" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
https://example.zendesk.com/hc/en-us/sections/<b>21857469</b>-Section-name
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Existing article ID" info="optional">
|
||||
<form-entry label="现有的文章ID" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="articleId" @keydown.enter="resolve()">
|
||||
</form-entry>
|
||||
<form-entry label="Locale" info="optional">
|
||||
<form-entry label="语言环境" info="可选的">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="locale" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Default:</b> en-us
|
||||
<b>默认:</b> en-us
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Template">
|
||||
<form-entry label="模板">
|
||||
<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">Configure templates</a>
|
||||
<a href="javascript:void(0)" @click="configureTemplates">配置模板</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
<div class="modal__info">
|
||||
<b>ProTip:</b> You can provide values for <code>title</code>, <code>tags</code> and
|
||||
<code>status</code> in the <a href="javascript:void(0)" @click="openFileProperties">file properties</a>.
|
||||
<b>提示:</b> 在<a href="javascript:void(0)" @click="openFileProperties">文件属性</a>中您可以为 <code>title</code>, <code>tags</code> 和
|
||||
<code>status</code>提供值。
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button button--resolve" @click="resolve()">Ok</button>
|
||||
<button class="button" @click="config.reject()">取消</button>
|
||||
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
@ -79,16 +79,16 @@ turndown:
|
||||
|
||||
# GitHub/GitLab/Gitee/Gitea commit messages
|
||||
git:
|
||||
createFileMessage: '{{path}} created from https://edit.qicoder.com/'
|
||||
updateFileMessage: '{{path}} updated from https://edit.qicoder.com/'
|
||||
deleteFileMessage: '{{path}} deleted from https://edit.qicoder.com/'
|
||||
createFileMessage: '{{path}} created from https://stackedit.cn/'
|
||||
updateFileMessage: '{{path}} updated from https://stackedit.cn/'
|
||||
deleteFileMessage: '{{path}} deleted from https://stackedit.cn/'
|
||||
|
||||
# Default content for new files
|
||||
newFileContent: |
|
||||
|
||||
|
||||
|
||||
> Written with [StackEdit](https://edit.qicoder.com/).
|
||||
> Written with [StackEdit](https://stackedit.cn/).
|
||||
|
||||
# Default properties for new files
|
||||
newFileProperties: |
|
||||
|
@ -1,7 +1,7 @@
|
||||
export default () => ({
|
||||
main: {
|
||||
id: 'main',
|
||||
name: '主工作区',
|
||||
name: '主文档空间',
|
||||
// The rest will be filled by the workspace/workspacesById getter
|
||||
},
|
||||
});
|
||||
|
@ -1,9 +1,9 @@
|
||||
**Where is my data stored?**
|
||||
**我的数据存储在哪里?**
|
||||
|
||||
If your workspace is not synced, your files are stored inside your browser and nowhere else.
|
||||
如果您的文档空间没有同步,则文件存储在浏览器中,无处可寻。
|
||||
|
||||
We recommend syncing your workspace to make sure files won't be lost in case your browser data is cleared. Self-hosted CouchDB or GitLab backends are well suited for privacy.
|
||||
我们建议同步您的文档空间,以确保在清除浏览器数据的情况下不会丢失文件。自托管Gitea后端非常适合保证隐私。
|
||||
|
||||
**Can StackEdit access my data without telling me?**
|
||||
**StackEdit可以访问我的数据而不告诉我吗?**
|
||||
|
||||
StackEdit is a browser-based application. The access tokens issued by Google, Dropbox, GitHub, Gitee... are stored in your browser and are not sent to any kind of backend or 3^rd^ party so your data won't be accessed by anyone.
|
||||
StackEdit是一个基于浏览器的应用程序。Gitee,Github,Dropbox ...发出的访问令牌存储在您的浏览器中,不会发送到任何形式的后端或第三方,因此任何人都不会访问您的数据。
|
||||
|
@ -54,516 +54,516 @@ export default [
|
||||
new Feature(
|
||||
'explorer',
|
||||
'资源管理器',
|
||||
'使用文件资源管理器管理工作区中的文件和文件夹。',
|
||||
'使用文件资源管理器管理文档空间中的文件和文件夹。',
|
||||
[
|
||||
new Feature(
|
||||
'createFile',
|
||||
'File creator',
|
||||
'Use the file explorer to create a new file in your workspace.',
|
||||
'文件创建',
|
||||
'使用文件资源管理器在文档空间中创建一个新文件。',
|
||||
),
|
||||
new Feature(
|
||||
'switchFile',
|
||||
'File switcher',
|
||||
'Use the file explorer to switch from one file to another in your workspace.',
|
||||
'文件切换',
|
||||
'使用文件资源管理器在文档空间中从一个文件切换到另一个文件。',
|
||||
),
|
||||
new Feature(
|
||||
'createFolder',
|
||||
'Folder creator',
|
||||
'Use the file explorer to create a new folder in your workspace.',
|
||||
'文件夹创建',
|
||||
'使用文件资源管理器在文档空间中创建一个新文件夹。',
|
||||
),
|
||||
new Feature(
|
||||
'moveFile',
|
||||
'File mover',
|
||||
'Drag a file in the file explorer to move it in another folder.',
|
||||
'文件移动',
|
||||
'在文件管理器中拖动一个文件到另一个文件夹。',
|
||||
),
|
||||
new Feature(
|
||||
'moveFolder',
|
||||
'Folder mover',
|
||||
'Drag a folder in the file explorer to move it in another folder.',
|
||||
'文件夹移动',
|
||||
'在文件管理器中拖动一个文件夹到另一个文件夹。',
|
||||
),
|
||||
new Feature(
|
||||
'renameFile',
|
||||
'File renamer',
|
||||
'Use the file explorer to rename a file in your workspace.',
|
||||
'文件重命名',
|
||||
'使用文件资源管理器重命名文档空间中的文件。',
|
||||
),
|
||||
new Feature(
|
||||
'renameFolder',
|
||||
'Folder renamer',
|
||||
'Use the file explorer to rename a folder in your workspace.',
|
||||
'文件夹重命名',
|
||||
'使用文件资源管理器重命名文档空间中的文件夹。',
|
||||
),
|
||||
new Feature(
|
||||
'removeFile',
|
||||
'File remover',
|
||||
'Use the file explorer to remove a file in your workspace.',
|
||||
'文件删除',
|
||||
'使用文件资源管理器删除文档空间中的文件。',
|
||||
),
|
||||
new Feature(
|
||||
'removeFolder',
|
||||
'Folder remover',
|
||||
'Use the file explorer to remove a folder in your workspace.',
|
||||
'文件夹删除',
|
||||
'使用文件资源管理器删除文档空间中的文件夹。',
|
||||
),
|
||||
],
|
||||
),
|
||||
new Feature(
|
||||
'buttonBar',
|
||||
'Button bar expert',
|
||||
'Use the button bar to customize the editor layout and to toggle features.',
|
||||
'按钮栏',
|
||||
'使用按钮栏自定义编辑器布局并切换功能。',
|
||||
[
|
||||
new Feature(
|
||||
'toggleNavigationBar',
|
||||
'Navigation bar toggler',
|
||||
'Use the button bar to toggle the navigation bar.',
|
||||
'导航栏切换',
|
||||
'使用按钮栏切换导航栏。',
|
||||
),
|
||||
new Feature(
|
||||
'toggleSidePreview',
|
||||
'Side preview toggler',
|
||||
'Use the button bar to toggle the side preview.',
|
||||
'切换侧边预览',
|
||||
'使用按钮栏切换侧边预览。',
|
||||
),
|
||||
new Feature(
|
||||
'toggleEditor',
|
||||
'Editor toggler',
|
||||
'Use the button bar to toggle the editor.',
|
||||
'切换编辑器',
|
||||
'使用按钮栏切换编辑器。',
|
||||
),
|
||||
new Feature(
|
||||
'toggleFocusMode',
|
||||
'Focused',
|
||||
'Use the button bar to toggle the focus mode. This mode keeps the caret vertically centered while typing.',
|
||||
'切换焦点模式',
|
||||
'使用按钮栏切换焦点模式。此模式在键入时将其垂直居中。',
|
||||
),
|
||||
new Feature(
|
||||
'toggleScrollSync',
|
||||
'Scroll sync toggler',
|
||||
'Use the button bar to toggle the scroll sync feature. This feature links the editor and the preview scrollbars.',
|
||||
'换滚动同步',
|
||||
'使用按钮栏切换滚动同步功能。此功能链接编辑器和预览滚动条。',
|
||||
),
|
||||
new Feature(
|
||||
'toggleStatusBar',
|
||||
'Status bar toggler',
|
||||
'Use the button bar to toggle the status bar.',
|
||||
'状态栏切换器',
|
||||
'使用按钮栏切换状态栏。',
|
||||
),
|
||||
],
|
||||
),
|
||||
new Feature(
|
||||
'signIn',
|
||||
'登录',
|
||||
'使用 Google 登录,同步您的主工作区并解锁功能。',
|
||||
'使用 Gitee 登录,同步您的主文档空间并解锁功能。',
|
||||
[
|
||||
new Feature(
|
||||
'syncMainWorkspace',
|
||||
'主工作区已同步',
|
||||
'使用 Google 登录以将您的主工作区与您的 Google Drive 应用数据文件夹同步。',
|
||||
'主文档空间已同步',
|
||||
'使用 Gitee 登录以将您的主文档空间与您的默认空间stackedit-app-data仓库数据同步。',
|
||||
),
|
||||
new Feature(
|
||||
'sponsor',
|
||||
'赞助',
|
||||
'使用 Google 登录并赞助 StackEdit 以解锁 PDF 和 Pandoc 导出。',
|
||||
'使用 Google 登录并赞助 StackEdit 以解锁 PDF 和 Pandoc 导出。(暂不支持赞助)',
|
||||
),
|
||||
],
|
||||
),
|
||||
new Feature(
|
||||
'workspaces',
|
||||
'Workspace expert',
|
||||
'使用工作区菜单创建各种工作区并对其进行管理。',
|
||||
'文档空间菜单',
|
||||
'使用文档空间菜单创建各种文档空间并对其进行管理。',
|
||||
[
|
||||
new Feature(
|
||||
'addCouchdbWorkspace',
|
||||
'CouchDB workspace creator',
|
||||
'Use the workspace menu to create a CouchDB workspace.',
|
||||
'创建CouchDB文档空间',
|
||||
'使用文档空间菜单创建CouchDB文档空间。',
|
||||
),
|
||||
new Feature(
|
||||
'addGithubWorkspace',
|
||||
'GitHub workspace creator',
|
||||
'Use the workspace menu to create a GitHub workspace.',
|
||||
'创建GitHub文档空间',
|
||||
'使用文档空间菜单创建GitHub文档空间。',
|
||||
),
|
||||
new Feature(
|
||||
'addGiteeWorkspace',
|
||||
'Gitee workspace creator',
|
||||
'Use the workspace menu to create a Gitee workspace.',
|
||||
'创建Gitee文档空间',
|
||||
'使用文档空间菜单创建Gitee文档空间。',
|
||||
),
|
||||
new Feature(
|
||||
'addGitlabWorkspace',
|
||||
'GitLab workspace creator',
|
||||
'Use the workspace menu to create a GitLab workspace.',
|
||||
'创建Gitlab文档空间',
|
||||
'使用文档空间菜单创建GitLab文档空间。',
|
||||
),
|
||||
new Feature(
|
||||
'addGiteaWorkspace',
|
||||
'Gitea workspace creator',
|
||||
'Use the workspace menu to create a Gitea workspace.',
|
||||
'创建Gitea文档空间',
|
||||
'使用文档空间菜单创建Gitea文档空间。',
|
||||
),
|
||||
new Feature(
|
||||
'addGoogleDriveWorkspace',
|
||||
'Google Drive workspace creator',
|
||||
'Use the workspace menu to create a Google Drive workspace.',
|
||||
'创建Google Drive文档空间',
|
||||
'使用文档空间菜单创建Google Drive文档空间。',
|
||||
),
|
||||
new Feature(
|
||||
'renameWorkspace',
|
||||
'Workspace renamer',
|
||||
'Use the "Manage workspaces" dialog to rename a workspace.',
|
||||
'文档空间重命名',
|
||||
'使用“管理文档空间”对话框重命名文档空间。',
|
||||
),
|
||||
new Feature(
|
||||
'removeWorkspace',
|
||||
'Workspace remover',
|
||||
'Use the "Manage workspaces" dialog to remove a workspace locally.',
|
||||
'文档空间删除',
|
||||
'使用“管理文档空间”对话框在本地删除文档空间。',
|
||||
),
|
||||
],
|
||||
),
|
||||
new Feature(
|
||||
'manageAccounts',
|
||||
'Account manager',
|
||||
'Link all kinds of external accounts and use the "Accounts" dialog to manage them.',
|
||||
'账号管理',
|
||||
'链接各种外部账号,并使用“账号”对话框来管理它们。',
|
||||
[
|
||||
new Feature(
|
||||
'addBloggerAccount',
|
||||
'Blogger user',
|
||||
'Link your Blogger account to StackEdit.',
|
||||
'Blogger账号',
|
||||
'将您的Blogger账号链接到Stackedit。',
|
||||
),
|
||||
new Feature(
|
||||
'addDropboxAccount',
|
||||
'Dropbox user',
|
||||
'Link your Dropbox account to StackEdit.',
|
||||
'Dropbox账号',
|
||||
'将您的Dropbox账号链接到Stackedit。',
|
||||
),
|
||||
new Feature(
|
||||
'addGitHubAccount',
|
||||
'GitHub user',
|
||||
'Link your GitHub account to StackEdit.',
|
||||
'GitHub账号',
|
||||
'将您的Github账号链接到Stackedit。',
|
||||
),
|
||||
new Feature(
|
||||
'addGiteeAccount',
|
||||
'Gitee user',
|
||||
'Link your Gitee account to StackEdit.',
|
||||
'Gitee账号',
|
||||
'将您的Gitee账号链接到Stackedit。',
|
||||
),
|
||||
new Feature(
|
||||
'addGitLabAccount',
|
||||
'GitLab user',
|
||||
'Link your GitLab account to StackEdit.',
|
||||
'GitLab账号',
|
||||
'将您的Gitlab账号链接到Stackedit。',
|
||||
),
|
||||
new Feature(
|
||||
'addGiteaAccount',
|
||||
'Gitea user',
|
||||
'Link your Gitea account to StackEdit.',
|
||||
'Gitea账号',
|
||||
'将您的Gitea账号链接到Stackedit。',
|
||||
),
|
||||
new Feature(
|
||||
'addGoogleDriveAccount',
|
||||
'Google Drive user',
|
||||
'Link your Google Drive account to StackEdit.',
|
||||
'Google Drive账号',
|
||||
'将您的Google Drive账号链接到Stackedit。',
|
||||
),
|
||||
new Feature(
|
||||
'addGooglePhotosAccount',
|
||||
'Google Photos user',
|
||||
'Link your Google Photos account to StackEdit.',
|
||||
'Google Photos账号',
|
||||
'将您的Google Photos账号链接到Stackedit。',
|
||||
),
|
||||
new Feature(
|
||||
'addWordpressAccount',
|
||||
'WordPress user',
|
||||
'Link your WordPress account to StackEdit.',
|
||||
'WordPress账号',
|
||||
'将您的WordPress账号链接到Stackedit。',
|
||||
),
|
||||
new Feature(
|
||||
'addZendeskAccount',
|
||||
'Zendesk user',
|
||||
'Link your Zendesk account to StackEdit.',
|
||||
'Zendesk账号',
|
||||
'将您的Zendesk账号链接到Stackedit。',
|
||||
),
|
||||
new Feature(
|
||||
'removeAccount',
|
||||
'Revoker',
|
||||
'Use the "Accounts" dialog to remove access to an external account.',
|
||||
'移除账号',
|
||||
'使用“账号”对话框删除对外部账号的访问。',
|
||||
),
|
||||
],
|
||||
),
|
||||
new Feature(
|
||||
'syncFiles',
|
||||
'File synchronizer',
|
||||
'Master the "Synchronize" menu by opening and saving files with all kinds of external accounts.',
|
||||
'文件同步器',
|
||||
'通过打开和保存各种外部账号的文件来掌握“同步”菜单。',
|
||||
[
|
||||
new Feature(
|
||||
'openFromDropbox',
|
||||
'Dropbox reader',
|
||||
'Use the "Synchronize" menu to open a file from your Dropbox account.',
|
||||
'Dropbox阅读器',
|
||||
'使用“同步”菜单从您的Dropbox账号打开文件。',
|
||||
),
|
||||
new Feature(
|
||||
'saveOnDropbox',
|
||||
'Dropbox writer',
|
||||
'Use the "Synchronize" menu to save a file in your Dropbox account.',
|
||||
'Dropbox保存',
|
||||
'使用“同步”菜单将文件保存在您的Dropbox账号中。',
|
||||
),
|
||||
new Feature(
|
||||
'openFromGithub',
|
||||
'GitHub reader',
|
||||
'Use the "Synchronize" menu to open a file from a GitHub repository.',
|
||||
'Github阅读器',
|
||||
'使用“同步”菜单从GitHub仓库打开文件。',
|
||||
),
|
||||
new Feature(
|
||||
'saveOnGithub',
|
||||
'GitHub writer',
|
||||
'Use the "Synchronize" menu to save a file in a GitHub repository.',
|
||||
'GitHub保存',
|
||||
'使用“同步”菜单将文件保存在GitHub仓库中。',
|
||||
),
|
||||
new Feature(
|
||||
'openFromGitee',
|
||||
'Gitee reader',
|
||||
'Use the "Synchronize" menu to open a file from a Gitee repository.',
|
||||
'Gitee阅读器',
|
||||
'使用“同步”菜单从Gitee仓库打开文件。',
|
||||
),
|
||||
new Feature(
|
||||
'saveOnGitee',
|
||||
'Gitee writer',
|
||||
'Use the "Synchronize" menu to save a file in a Gitee repository.',
|
||||
'Gitee保存',
|
||||
'使用“同步”菜单将文件保存在Gitee仓库中。',
|
||||
),
|
||||
new Feature(
|
||||
'saveOnGist',
|
||||
'Gist writer',
|
||||
'Use the "Synchronize" menu to save a file in a Gist.',
|
||||
'Gist保存',
|
||||
'使用“同步”菜单将文件保存在GIST中。',
|
||||
),
|
||||
new Feature(
|
||||
'openFromGitlab',
|
||||
'GitLab reader',
|
||||
'Use the "Synchronize" menu to open a file from a GitLab repository.',
|
||||
'GitLab阅读器',
|
||||
'使用“同步”菜单从GitLab仓库打开文件。',
|
||||
),
|
||||
new Feature(
|
||||
'saveOnGitlab',
|
||||
'GitLab writer',
|
||||
'Use the "Synchronize" menu to save a file in a GitLab repository.',
|
||||
'GitLab保存',
|
||||
'使用“同步”菜单将文件保存在GitLab仓库中。',
|
||||
),
|
||||
new Feature(
|
||||
'openFromGitea',
|
||||
'Gitea reader',
|
||||
'Use the "Synchronize" menu to open a file from a Gitea repository.',
|
||||
'Gitea阅读器',
|
||||
'使用“同步”菜单从Gitea仓库打开文件。',
|
||||
),
|
||||
new Feature(
|
||||
'saveOnGitea',
|
||||
'Gitea writer',
|
||||
'Use the "Synchronize" menu to save a file in a Gitea repository.',
|
||||
'Gitea保存',
|
||||
'使用“同步”菜单将文件保存在Gitea仓库中。',
|
||||
),
|
||||
new Feature(
|
||||
'openFromGoogleDrive',
|
||||
'Google Drive reader',
|
||||
'Use the "Synchronize" menu to open a file from your Google Drive account.',
|
||||
'Google Drive阅读器',
|
||||
'使用“同步”菜单从您的Google Drive账号打开文件。',
|
||||
),
|
||||
new Feature(
|
||||
'saveOnGoogleDrive',
|
||||
'Google Drive writer',
|
||||
'Use the "Synchronize" menu to save a file in your Google Drive account.',
|
||||
'Google Drive保存',
|
||||
'使用“同步”菜单将文件保存在您的Google Drive账号中。',
|
||||
),
|
||||
new Feature(
|
||||
'triggerSync',
|
||||
'Sync trigger',
|
||||
'Use the "Synchronize" menu or the navigation bar to manually trigger synchronization.',
|
||||
'同步触发器',
|
||||
'使用“同步”菜单或导航栏手动触发同步。',
|
||||
),
|
||||
new Feature(
|
||||
'syncMultipleLocations',
|
||||
'Multi-sync',
|
||||
'Use the "Synchronize" menu to synchronize a file with multiple external locations.',
|
||||
'多方同步',
|
||||
'使用“同步”菜单将文件与多个外部位置同步。',
|
||||
),
|
||||
new Feature(
|
||||
'removeSyncLocation',
|
||||
'Desynchronizer',
|
||||
'Use the "File synchronization" dialog to remove a sync location.',
|
||||
'删除同步',
|
||||
'使用“文件同步”对话框删除同步位置。',
|
||||
),
|
||||
],
|
||||
),
|
||||
new Feature(
|
||||
'publishFiles',
|
||||
'File publisher',
|
||||
'Master the "Publish" menu by publishing files to all kinds of external accounts.',
|
||||
'文件发布',
|
||||
'通过将文件发布到各种外部账号中来掌握“发布”菜单。',
|
||||
[
|
||||
new Feature(
|
||||
'publishToBlogger',
|
||||
'Blogger publisher',
|
||||
'Use the "Publish" menu to publish a Blogger article.',
|
||||
'Blogger发布',
|
||||
'使用“发布”菜单发布博客文章。',
|
||||
),
|
||||
new Feature(
|
||||
'publishToBloggerPage',
|
||||
'Blogger Page publisher',
|
||||
'Use the "Publish" menu to publish a Blogger page.',
|
||||
'Blogger页面发布',
|
||||
'使用“发布”菜单发布Blogger页面。',
|
||||
),
|
||||
new Feature(
|
||||
'publishToDropbox',
|
||||
'Dropbox publisher',
|
||||
'Use the "Publish" menu to publish a file to your Dropbox account.',
|
||||
'Dropbox发布',
|
||||
'使用“发布”菜单将文件发布到您的Dropbox账号。',
|
||||
),
|
||||
new Feature(
|
||||
'publishToGithub',
|
||||
'GitHub publisher',
|
||||
'Use the "Publish" menu to publish a file to a GitHub repository.',
|
||||
'GitHub发布',
|
||||
'使用“发布”菜单将文件发布到GitHub仓库。',
|
||||
),
|
||||
new Feature(
|
||||
'publishToGist',
|
||||
'Gist publisher',
|
||||
'Use the "Publish" menu to publish a file to a Gist.',
|
||||
'Gist发布',
|
||||
'使用“发布”菜单将文件发布到GIST。',
|
||||
),
|
||||
new Feature(
|
||||
'publishToGitee',
|
||||
'Gitee publisher',
|
||||
'Use the "Publish" menu to publish a file to a Gitee repository.',
|
||||
'Gitee发布',
|
||||
'使用“发布”菜单将文件发布到Gitee仓库。',
|
||||
),
|
||||
new Feature(
|
||||
'publishToGitlab',
|
||||
'GitLab publisher',
|
||||
'Use the "Publish" menu to publish a file to a GitLab repository.',
|
||||
'GitLab发布',
|
||||
'使用“发布”菜单将文件发布到GitLab仓库中。',
|
||||
),
|
||||
new Feature(
|
||||
'publishToGitea',
|
||||
'Gitea publisher',
|
||||
'Use the "Publish" menu to publish a file to a Gitea repository.',
|
||||
'Gitea发布',
|
||||
'使用“发布”菜单将文件发布到Gitea仓库。',
|
||||
),
|
||||
new Feature(
|
||||
'publishToGoogleDrive',
|
||||
'Google Drive publisher',
|
||||
'Use the "Publish" menu to publish a file to your Google Drive account.',
|
||||
'Google Drive发布',
|
||||
'使用“发布”菜单将文件发布到您的Google Drive账号。',
|
||||
),
|
||||
new Feature(
|
||||
'publishToWordPress',
|
||||
'WordPress publisher',
|
||||
'Use the "Publish" menu to publish a WordPress article.',
|
||||
'WordPress发布',
|
||||
'使用“发布”菜单发布WordPress文章。',
|
||||
),
|
||||
new Feature(
|
||||
'publishToZendesk',
|
||||
'Zendesk publisher',
|
||||
'Use the "Publish" menu to publish a Zendesk Help Center article.',
|
||||
'Zendesk发布',
|
||||
'使用“发布”菜单发布Zendesk帮助中心文章。',
|
||||
),
|
||||
new Feature(
|
||||
'triggerPublish',
|
||||
'Publication reviser',
|
||||
'Use the "Publish" menu or the navigation bar to manually update publications.',
|
||||
'更新发布',
|
||||
'使用“发布”菜单或导航栏手动更新发布。',
|
||||
),
|
||||
new Feature(
|
||||
'publishMultipleLocations',
|
||||
'Multi-publication',
|
||||
'Use the "Publish" menu to publish a file to multiple external locations.',
|
||||
'多方发布',
|
||||
'使用“发布”菜单将文件发布到多个外部位置。',
|
||||
),
|
||||
new Feature(
|
||||
'removePublishLocation',
|
||||
'Unpublisher',
|
||||
'Use the "File publication" dialog to remove a publish location.',
|
||||
'删除发布',
|
||||
'使用“文件发布”对话框删除发布位置。',
|
||||
),
|
||||
],
|
||||
),
|
||||
new Feature(
|
||||
'manageHistory',
|
||||
'Historian',
|
||||
'Use the "File history" menu to see version history and restore old versions of the current file.',
|
||||
'文件历史记录',
|
||||
'使用“文件历史记录”菜单查看版本历史记录并恢复当前文件的旧版本。',
|
||||
[
|
||||
new Feature(
|
||||
'restoreVersion',
|
||||
'Restorer',
|
||||
'Use the "File history" menu to restore an old version of the current file.',
|
||||
'恢复',
|
||||
'使用“文件历史记录”菜单来还原当前文件的旧版本。',
|
||||
),
|
||||
new Feature(
|
||||
'chooseHistory',
|
||||
'History chooser',
|
||||
'Select a different history for a file that is synced with multiple external locations.',
|
||||
'历史版本选择',
|
||||
'选择与多个外部位置同步的文件的不同历史记录。',
|
||||
),
|
||||
],
|
||||
),
|
||||
new Feature(
|
||||
'manageProperties',
|
||||
'Property expert',
|
||||
'Use the "File properties" dialog to change properties for the current file.',
|
||||
'文件属性',
|
||||
'使用“文件属性”对话框更改当前文件的属性。',
|
||||
[
|
||||
new Feature(
|
||||
'setMetadata',
|
||||
'Metadata setter',
|
||||
'Use the "File properties" dialog to set metadata for the current file.',
|
||||
'元数据设置',
|
||||
'使用“文件属性”对话框为当前文件设置元数据。',
|
||||
),
|
||||
new Feature(
|
||||
'changePreset',
|
||||
'Preset changer',
|
||||
'Use the "File properties" dialog to change the Markdown engine preset.',
|
||||
'预设更改',
|
||||
'使用“文件属性”对话框更改Markdown引擎预设。',
|
||||
),
|
||||
new Feature(
|
||||
'changeExtension',
|
||||
'Extension expert',
|
||||
'Use the "File properties" dialog to enable, disable or configure Markdown engine extensions.',
|
||||
'扩展配置',
|
||||
'使用“文件属性”对话框启用,禁用或配置Markdown引擎扩展。',
|
||||
),
|
||||
],
|
||||
),
|
||||
new Feature(
|
||||
'comment',
|
||||
'Comment expert',
|
||||
'Start and remove discussions, add and remove comments.',
|
||||
'评论',
|
||||
'启动并删除讨论,添加和删除评论。',
|
||||
[
|
||||
new Feature(
|
||||
'createDiscussion',
|
||||
'Discussion starter',
|
||||
'Use the "comment" button to start a new discussion.',
|
||||
'启动讨论',
|
||||
'使用“评论”按钮开始新的讨论。',
|
||||
),
|
||||
new Feature(
|
||||
'addComment',
|
||||
'Commenter',
|
||||
'Use the discussion gutter to add a comment to an existing discussion.',
|
||||
'添加评论',
|
||||
'使用讨论在现有讨论中添加评论。',
|
||||
),
|
||||
new Feature(
|
||||
'removeComment',
|
||||
'Moderator',
|
||||
'Use the discussion gutter to remove a comment in a discussion.',
|
||||
'删除评论',
|
||||
'使用讨论在讨论中删除评论。',
|
||||
),
|
||||
new Feature(
|
||||
'removeDiscussion',
|
||||
'Discussion closer',
|
||||
'Use the discussion gutter to remove a discussion.',
|
||||
'关闭讨论',
|
||||
'使用讨论去删除讨论。',
|
||||
),
|
||||
],
|
||||
),
|
||||
new Feature(
|
||||
'importExport',
|
||||
'Import/export',
|
||||
'Use the "Import/export" menu to import and export files.',
|
||||
'导入/导出',
|
||||
'使用“导入/导出”菜单以导入和导出文件。',
|
||||
[
|
||||
new Feature(
|
||||
'importMarkdown',
|
||||
'Markdown importer',
|
||||
'Use the "Import/export" menu to import a Markdown file from disk.',
|
||||
'Markdown导入',
|
||||
'使用“导入/导出”菜单从磁盘导入Markdown文件。',
|
||||
),
|
||||
new Feature(
|
||||
'exportMarkdown',
|
||||
'Markdown exporter',
|
||||
'Use the "Import/export" menu to export a Markdown file to disk.',
|
||||
'Markdown导出',
|
||||
'使用“导入/导出”菜单将Markdown文件导出到磁盘。',
|
||||
),
|
||||
new Feature(
|
||||
'importHtml',
|
||||
'HTML importer',
|
||||
'Use the "Import/export" menu to import an HTML file from disk and convert it to Markdown.',
|
||||
'HTML导入',
|
||||
'使用“导入/导出”菜单从磁盘导入HTML文件,然后将其转换为Markdown。',
|
||||
),
|
||||
new Feature(
|
||||
'exportHtml',
|
||||
'HTML exporter',
|
||||
'Use the "Import/export" menu to export a file to disk as an HTML file using a Handlebars template.',
|
||||
'HTML导出',
|
||||
'使用“导入/导出”菜单和Handlebars模板将文件导出到磁盘作为HTML文件。',
|
||||
),
|
||||
new Feature(
|
||||
'exportPdf',
|
||||
'PDF exporter',
|
||||
'Use the "Import/export" menu to export a file to disk as a PDF file.',
|
||||
'PDF导出',
|
||||
'使用“导入/导出”菜单将文件导出到磁盘作为PDF文件。',
|
||||
),
|
||||
new Feature(
|
||||
'exportPandoc',
|
||||
'Pandoc exporter',
|
||||
'Use the "Import/export" menu to export a file to disk using Pandoc.',
|
||||
'Pandoc导出',
|
||||
'使用“导入/导出”菜单将文件导出到使用Pandoc的磁盘。',
|
||||
),
|
||||
],
|
||||
),
|
||||
new Feature(
|
||||
'manageSettings',
|
||||
'Settings expert',
|
||||
'Use the "Settings" dialog to tweak the application behaviors and change keyboard shortcuts.',
|
||||
'管理设置',
|
||||
'使用“设置”对话框调整应用程序行为并更改键盘快捷键。',
|
||||
[
|
||||
new Feature(
|
||||
'changeSettings',
|
||||
'Tweaker',
|
||||
'Use the "Settings" dialog to tweak the application behaviors.',
|
||||
'更新设置',
|
||||
'使用“设置”对话框调整应用程序行为。',
|
||||
),
|
||||
new Feature(
|
||||
'changeShortcuts',
|
||||
'Shortcut editor',
|
||||
'Use the "Settings" dialog to change keyboard shortcuts.',
|
||||
'编辑快捷键',
|
||||
'使用“设置”对话框更改键盘快捷键。',
|
||||
),
|
||||
],
|
||||
),
|
||||
new Feature(
|
||||
'manageTemplates',
|
||||
'Template expert',
|
||||
'Use the "Templates" dialog to create, remove or modify Handlebars templates.',
|
||||
'管理模板',
|
||||
'使用“模板”对话框创建,删除或修改Handlebars模板。',
|
||||
[
|
||||
new Feature(
|
||||
'addTemplate',
|
||||
'Template creator',
|
||||
'Use the "Templates" dialog to create a Handlebars template.',
|
||||
'模板创建',
|
||||
'使用“模板”对话框创建一个Handlebars模板。',
|
||||
),
|
||||
new Feature(
|
||||
'removeTemplate',
|
||||
'Template remover',
|
||||
'Use the "Templates" dialog to remove a Handlebars template.',
|
||||
'模板删除',
|
||||
'使用“模板”对话框删除Handlebars模板。',
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -7,91 +7,91 @@ const simpleModal = (contentHtml, rejectText, resolveText) => ({
|
||||
/* eslint sort-keys: "error" */
|
||||
export default {
|
||||
commentDeletion: simpleModal(
|
||||
'<p>You are about to delete a comment. Are you sure?</p>',
|
||||
'No',
|
||||
'Yes, delete',
|
||||
'<p>您将要删除评论。你确定吗?</p>',
|
||||
'取消',
|
||||
'确认删除',
|
||||
),
|
||||
discussionDeletion: simpleModal(
|
||||
'<p>You are about to delete a discussion. Are you sure?</p>',
|
||||
'No',
|
||||
'Yes, delete',
|
||||
'<p>您将要删除讨论。你确定吗?</p>',
|
||||
'取消',
|
||||
'确认删除',
|
||||
),
|
||||
fileRestoration: simpleModal(
|
||||
'<p>You are about to revert some changes. Are you sure?</p>',
|
||||
'No',
|
||||
'Yes, revert',
|
||||
'<p>您将要恢复一些更改。你确定吗?</p>',
|
||||
'取消',
|
||||
'确认恢复',
|
||||
),
|
||||
folderDeletion: simpleModal(
|
||||
config => `<p>You are about to delete the folder <b>${config.item.name}</b>. Its files will be moved to Trash. Are you sure?</p>`,
|
||||
'No',
|
||||
'Yes, delete',
|
||||
config => `<p>您将删除文件夹<b>${config.item.name}</b>。它的文件将移至回收站。你确定吗?</p>`,
|
||||
'取消',
|
||||
'确认删除',
|
||||
),
|
||||
pathConflict: simpleModal(
|
||||
config => `<p><b>${config.item.name}</b> already exists. Do you want to add a suffix?</p>`,
|
||||
'No',
|
||||
'Yes, add suffix',
|
||||
config => `<p><b>${config.item.name}</b>已经存在。您要添加后缀吗?</p>`,
|
||||
'取消',
|
||||
'确认添加',
|
||||
),
|
||||
paymentSuccess: simpleModal(
|
||||
'<h3>Thank you for your payment!</h3><p>Your sponsorship will be active in a minute.</p>',
|
||||
'Ok',
|
||||
'<h3>感谢您的付款!</h3> <p>您的赞助将在一分钟内活跃。</p>',
|
||||
'好的',
|
||||
),
|
||||
providerRedirection: simpleModal(
|
||||
config => `<p>You are about to navigate to the <b>${config.name}</b> authorization page.</p>`,
|
||||
'Cancel',
|
||||
'Ok, go on',
|
||||
config => `<p>您将跳转到 <b>${config.name}</b> 授权页面。</p>`,
|
||||
'取消',
|
||||
'确认跳转',
|
||||
),
|
||||
removeWorkspace: simpleModal(
|
||||
'<p>You are about to remove a workspace locally. Are you sure?</p>',
|
||||
'No',
|
||||
'Yes, remove',
|
||||
'<p>您将要在本地删除文档空间ß。你确定吗?</p>',
|
||||
'取消',
|
||||
'确认删除',
|
||||
),
|
||||
reset: simpleModal(
|
||||
'<p>这将在本地清理所有工作区,你确定吗?</p>',
|
||||
'<p>这将在本地清理所有文档空间,你确定吗?</p>',
|
||||
'取消',
|
||||
'确认清理',
|
||||
),
|
||||
signInForComment: simpleModal(
|
||||
`<p>您必须使用 Google 登录才能开始评论。</p>
|
||||
<div class="modal__info"><b>注意:</b> 这将同步您的主工作区。</div>`,
|
||||
<div class="modal__info"><b>注意:</b> 这将同步您的主文档空间。</div>`,
|
||||
'取消',
|
||||
'确认登录',
|
||||
),
|
||||
signInForSponsorship: simpleModal(
|
||||
`<p>您必须使用 Google 登录才能赞助。</p>
|
||||
<div class="modal__info"><b>注意:</b> 这将同步您的主工作区。</div>`,
|
||||
<div class="modal__info"><b>注意:</b> 这将同步您的主文档空间。</div>`,
|
||||
'取消',
|
||||
'确认登录',
|
||||
),
|
||||
sponsorOnly: simpleModal(
|
||||
'<p>This feature is restricted to sponsors as it relies on server resources.</p>',
|
||||
'Ok, I understand',
|
||||
'<p>此功能仅限于赞助商,因为它依赖于服务器资源。</p>',
|
||||
'好的,我明白了',
|
||||
),
|
||||
stripName: simpleModal(
|
||||
config => `<p><b>${config.item.name}</b> contains illegal characters. Do you want to strip them?</p>`,
|
||||
'No',
|
||||
'Yes, strip',
|
||||
config => `<p><b>${config.item.name}</b>包含非法字符。你想剥离它们吗?</p>`,
|
||||
'取消',
|
||||
'确认剥离',
|
||||
),
|
||||
tempFileDeletion: simpleModal(
|
||||
config => `<p>You are about to permanently delete the temporary file <b>${config.item.name}</b>. Are you sure?</p>`,
|
||||
'No',
|
||||
'Yes, delete',
|
||||
config => `<p>您将永久删除临时文件<b>${config.item.name}</b>。你确定吗?</p>`,
|
||||
'取消',
|
||||
'确认删除',
|
||||
),
|
||||
tempFolderDeletion: simpleModal(
|
||||
'<p>You are about to permanently delete all the temporary files. Are you sure?</p>',
|
||||
'No',
|
||||
'Yes, delete all',
|
||||
'<p>您将永久删除所有临时文件。你确定吗?</p>',
|
||||
'取消',
|
||||
'确认删除',
|
||||
),
|
||||
trashDeletion: simpleModal(
|
||||
'<p>Files in the trash are automatically deleted after 7 days of inactivity.</p>',
|
||||
'Ok',
|
||||
'<p>回收站中的文件在不活动7天后会自动删除。</p>',
|
||||
'好的',
|
||||
),
|
||||
unauthorizedName: simpleModal(
|
||||
config => `<p><b>${config.item.name}</b> is an unauthorized name.</p>`,
|
||||
'Ok',
|
||||
config => `<p><b>${config.item.name}</b>>是未经授权的名称。</p>`,
|
||||
'好的',
|
||||
),
|
||||
workspaceGoogleRedirection: simpleModal(
|
||||
'<p>StackEdit needs full Google Drive access to open this workspace.</p>',
|
||||
'Cancel',
|
||||
'Ok, grant',
|
||||
'<p>StackEdit需要完整的Google Drive访问才能打开此文档空间。</p>',
|
||||
'取消',
|
||||
'确认授权',
|
||||
),
|
||||
};
|
||||
|
@ -5,7 +5,7 @@
|
||||
<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://edit.qicoder.com/style.css" />
|
||||
<link rel="stylesheet" href="https://stackedit.cn/style.css" />
|
||||
</head>
|
||||
|
||||
{{#if pdf}}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<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://edit.qicoder.com/style.css" />
|
||||
<link rel="stylesheet" href="https://stackedit.cn/style.css" />
|
||||
</head>
|
||||
|
||||
{{#if pdf}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
# 欢迎来到 StackEdit!
|
||||
# 欢迎来到 StackEdit 中文版!
|
||||
|
||||
你好!我是你在 **StackEdit** 中的第一个 Markdown 文件。如果你想了解 StackEdit,可以阅读我的文章。如果你想玩 Markdown,你可以编辑我。完成后,您可以通过打开导航栏左角的**文件资源管理器**来创建新文件。
|
||||
|
||||
@ -30,23 +30,23 @@ StackEdit 将您的文件存储在您的浏览器中,这意味着您的所有
|
||||
|
||||
# 同步
|
||||
|
||||
同步是 StackEdit 的最大特点之一。它使您可以将工作区中的任何文件与存储在 **Google Drive**、**Dropbox** 和 **GitHub** 帐户中的其他文件同步。这使您可以继续在其他设备上写作,与您共享文件的人协作,轻松集成到您的工作流程中......同步机制在后台每分钟发生一次,下载、合并和上传文件修改。
|
||||
同步是 StackEdit 的最大特点之一。它使您可以将文档空间中的任何文件与存储在**Gitee** 和 **GitHub** 账号中的其他文件同步。这使您可以继续在其他设备上写作,与您共享文件的人协作,轻松集成到您的工作流程中......同步机制在后台每分钟发生一次,下载、合并和上传文件修改。
|
||||
|
||||
有两种类型的同步,它们可以相互补充:
|
||||
|
||||
- 工作区同步将自动同步您的所有文件、文件夹和设置。这将允许您在任何其他设备上获取您的工作区。
|
||||
> 要开始同步您的工作区,只需在菜单中使用 Google 登录。
|
||||
- 文档空间同步将自动同步您的所有文件、文件夹和设置。这将允许您在任何其他设备上获取您的文档空间。
|
||||
> 要开始同步您的文档空间,只需在菜单中使用 Google 登录。
|
||||
|
||||
- 文件同步将保持工作区的一个文件与**Google Drive**、**Dropbox**或**GitHub**中的一个或多个文件同步。
|
||||
> 在开始同步文件之前,您必须在**同步**子菜单中链接一个帐户。
|
||||
- 文件同步将保持文档空间的一个文件与**Gitee**或**GitHub**中的一个或多个文件同步。
|
||||
> 在开始同步文件之前,您必须在**同步**子菜单中链接一个账号。
|
||||
|
||||
## 打开一个文件
|
||||
|
||||
您可以通过打开 **同步** 子菜单并单击 **Open from** 从 **Google Drive**、**Dropbox** 或 **GitHub** 打开文件。在工作区中打开后,文件中的任何修改都将自动同步。
|
||||
您可以通过打开 **同步** 子菜单并单击 **Open from** 从**Gitee** 或 **GitHub** 打开文件。在文档空间中打开后,文件中的任何修改都将自动同步。
|
||||
|
||||
## 保存文件
|
||||
|
||||
您可以通过打开 **同步** 子菜单并单击 **Save on** 将工作区的任何文件保存到 **Google Drive**、**Dropbox** 或 **GitHub**。即使工作区中的文件已经同步,您也可以将其保存到另一个位置。 StackEdit 可以将一个文件与多个位置和帐户同步。
|
||||
您可以通过打开 **同步** 子菜单并单击 **Save on** 将文档空间的任何文件保存到**Gitee** 或 **GitHub**。即使文档空间中的文件已经同步,您也可以将其保存到另一个位置。 StackEdit 可以将一个文件与多个位置和账号同步。
|
||||
|
||||
##同步文件
|
||||
|
||||
@ -61,11 +61,11 @@ StackEdit 将您的文件存储在您的浏览器中,这意味着您的所有
|
||||
由于一个文件可以与多个位置同步,您可以通过单击**同步**子菜单中的**文件同步**列出和管理同步位置。这允许您列出和删除链接到您的文件的同步位置。
|
||||
|
||||
|
||||
# 出版物
|
||||
# 发布
|
||||
|
||||
在 StackEdit 中发布使您可以轻松地在线发布文件。对文件感到满意后,您可以将其发布到不同的托管平台,例如 **Blogger**、**Dropbox**、**Gist**、**GitHub**、**Google Drive**、* *WordPress** 和 **Zendesk**。使用 [Handlebars 模板](http://handlebarsjs.com/),您可以完全控制导出的内容。
|
||||
在 StackEdit 中发布使您可以轻松地在线发布文件。对文件感到满意后,您可以将其发布到不同的托管平台,例如 **Blogger**、**Gitee**、**Gist**、**GitHub**、**WordPress** 和 **Zendesk**。使用 [Handlebars 模板](http://handlebarsjs.com/),您可以完全控制导出的内容。
|
||||
|
||||
> 在开始发布之前,您必须在**发布**子菜单中链接一个帐户。
|
||||
> 在开始发布之前,您必须在**发布**子菜单中链接一个账号。
|
||||
|
||||
## 发布文件
|
||||
|
||||
@ -74,9 +74,9 @@ StackEdit 将您的文件存储在您的浏览器中,这意味着您的所有
|
||||
- Markdown:在可以解释的网站上发布 Markdown 文本(例如**GitHub**),
|
||||
- HTML:通过 Handlebars 模板发布转换为 HTML 的文件(例如在博客上)。
|
||||
|
||||
## 更新出版物
|
||||
## 更新发布
|
||||
|
||||
发布后,StackEdit 会将您的文件链接到该出版物,这使您可以轻松地重新发布它。一旦您修改了文件并想要更新您的出版物,请单击导航栏中的**立即发布**按钮。
|
||||
发布后,StackEdit 会将您的文件链接到该发布,这使您可以轻松地重新发布它。一旦您修改了文件并想要更新您的发布,请单击导航栏中的**立即发布**按钮。
|
||||
|
||||
> **注意:** 如果您没有要同步的文件,**立即同步**按钮将被禁用。
|
||||
|
||||
@ -85,11 +85,11 @@ StackEdit 将您的文件存储在您的浏览器中,这意味着您的所有
|
||||
由于一个文件可以与多个位置同步,您可以通过单击**同步**子菜单中的**文件同步**列出和管理同步位置。这允许您列出和删除链接到您的文件的同步位置。
|
||||
|
||||
|
||||
# 出版物
|
||||
# 发布
|
||||
|
||||
在 StackEdit 中发布使您可以轻松地在线发布文件。对文件感到满意后,您可以将其发布到不同的托管平台,例如 **Blogger**、**Dropbox**、**Gist**、**GitHub**、**Google Drive**、* *WordPress** 和 **Zendesk**。使用 [Handlebars 模板](http://handlebarsjs.com/),您可以完全控制导出的内容。
|
||||
在 StackEdit 中发布使您可以轻松地在线发布文件。对文件感到满意后,您可以将其发布到不同的托管平台,例如 **Blogger**、**Gitee**、**Gist**、**GitHub**、**WordPress** 和 **Zendesk**。使用 [Handlebars 模板](http://handlebarsjs.com/),您可以完全控制导出的内容。
|
||||
|
||||
> 在开始发布之前,您必须在**发布**子菜单中链接一个帐户。
|
||||
> 在开始发布之前,您必须在**发布**子菜单中链接一个账号。
|
||||
|
||||
## 发布文件
|
||||
|
||||
@ -98,9 +98,9 @@ StackEdit 将您的文件存储在您的浏览器中,这意味着您的所有
|
||||
- Markdown:在可以解释的网站上发布 Markdown 文本(例如**GitHub**),
|
||||
- HTML:通过 Handlebars 模板发布转换为 HTML 的文件(例如在博客上)。
|
||||
|
||||
## 更新出版物
|
||||
## 更新发布
|
||||
|
||||
发布后,StackEdit 会将您的文件链接到该出版物,这使您可以轻松地重新发布它。一旦您修改了文件并想要更新您的出版物,请单击导航栏中的**立即发布**按钮。
|
||||
发布后,StackEdit 会将您的文件链接到该发布,这使您可以轻松地重新发布它。一旦您修改了文件并想要更新您的发布,请单击导航栏中的**立即发布**按钮。
|
||||
|
||||
> **注意:** 如果您的文件尚未发布,则 **立即发布** 按钮将被禁用。
|
||||
|
||||
|
@ -11,7 +11,6 @@ export default {
|
||||
classState() {
|
||||
switch (this.providerId) {
|
||||
case 'googleDrive':
|
||||
case 'googleDriveAppData':
|
||||
case 'googleDriveWorkspace':
|
||||
return 'google-drive';
|
||||
case 'googlePhotos':
|
||||
@ -28,6 +27,7 @@ export default {
|
||||
return 'blogger';
|
||||
case 'couchdbWorkspace':
|
||||
return 'couchdb';
|
||||
case 'giteeAppData':
|
||||
case 'giteeWorkspace':
|
||||
return 'gitee';
|
||||
default:
|
||||
|
256
src/services/providers/giteeAppDataProvider.js
Normal file
256
src/services/providers/giteeAppDataProvider.js
Normal file
@ -0,0 +1,256 @@
|
||||
import store from '../../store';
|
||||
import giteeHelper from './helpers/giteeHelper';
|
||||
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: 'giteeAppData',
|
||||
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 giteeHelper.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 giteeHelper.uploadFile({
|
||||
owner: syncToken.name,
|
||||
repo: appDataRepo,
|
||||
branch: appDataBranch,
|
||||
token: syncToken,
|
||||
path: syncData.id,
|
||||
content: '',
|
||||
sha: gitWorkspaceSvc.shaByPath[syncData.id],
|
||||
});
|
||||
|
||||
// Return sync data to save
|
||||
return { syncData };
|
||||
},
|
||||
async removeWorkspaceItem({ syncData }) {
|
||||
if (gitWorkspaceSvc.shaByPath[syncData.id]) {
|
||||
const syncToken = store.getters['workspace/syncToken'];
|
||||
await giteeHelper.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 giteeHelper.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 downloadWorkspaceData({ token, syncData }) {
|
||||
if (!syncData) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const { sha, data } = await giteeHelper.downloadFile({
|
||||
owner: token.name,
|
||||
repo: appDataRepo,
|
||||
branch: appDataBranch,
|
||||
token,
|
||||
path: syncData.id,
|
||||
});
|
||||
gitWorkspaceSvc.shaByPath[syncData.id] = sha;
|
||||
const item = JSON.parse(data);
|
||||
return {
|
||||
item,
|
||||
syncData: {
|
||||
...syncData,
|
||||
hash: item.hash,
|
||||
sha,
|
||||
},
|
||||
};
|
||||
},
|
||||
async uploadWorkspaceContent({ token, content, file }) {
|
||||
const path = store.getters.gitPathsByItemId[file.id];
|
||||
const res = await giteeHelper.uploadFile({
|
||||
owner: token.name,
|
||||
repo: appDataRepo,
|
||||
branch: appDataBranch,
|
||||
token,
|
||||
path,
|
||||
content: Provider.serializeContent(content),
|
||||
sha: gitWorkspaceSvc.shaByPath[path],
|
||||
});
|
||||
|
||||
// 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,
|
||||
}) {
|
||||
const path = store.getters.gitPathsByItemId[item.id];
|
||||
if (!path) {
|
||||
return {
|
||||
syncData: {
|
||||
type: item.type,
|
||||
hash: item.hash,
|
||||
},
|
||||
};
|
||||
}
|
||||
const syncData = {
|
||||
id: path,
|
||||
type: item.type,
|
||||
hash: item.hash,
|
||||
};
|
||||
const res = await giteeHelper.uploadFile({
|
||||
token,
|
||||
owner: token.name,
|
||||
repo: appDataRepo,
|
||||
branch: appDataBranch,
|
||||
path,
|
||||
content: JSON.stringify(item),
|
||||
sha: gitWorkspaceSvc.shaByPath[path],
|
||||
});
|
||||
|
||||
return {
|
||||
syncData: {
|
||||
...syncData,
|
||||
sha: res.content.sha,
|
||||
},
|
||||
};
|
||||
},
|
||||
async listFileRevisions({ token, fileSyncDataId }) {
|
||||
const { owner, repo, branch } = {
|
||||
owner: token.name,
|
||||
repo: appDataRepo,
|
||||
branch: appDataBranch,
|
||||
};
|
||||
const entries = await giteeHelper.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 = `${giteeHelper.subPrefix}:${user.login}`;
|
||||
if (user.avatar_url && user.avatar_url.endsWith('.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,
|
||||
created: new Date(date).getTime(),
|
||||
};
|
||||
});
|
||||
},
|
||||
async loadFileRevision() {
|
||||
// Revisions are already loaded
|
||||
return false;
|
||||
},
|
||||
async getFileRevisionContent({
|
||||
token,
|
||||
contentId,
|
||||
fileSyncDataId,
|
||||
}) {
|
||||
const { data } = await giteeHelper.downloadFile({
|
||||
owner: token.name,
|
||||
repo: appDataRepo,
|
||||
branch: appDataBranch,
|
||||
token,
|
||||
path: fileSyncDataId,
|
||||
});
|
||||
return Provider.parseContent(data, contentId);
|
||||
},
|
||||
});
|
@ -87,7 +87,7 @@ export default new Provider({
|
||||
});
|
||||
}
|
||||
|
||||
badgeSvc.addBadge('addGithubWorkspace');
|
||||
badgeSvc.addBadge('addGiteeWorkspace');
|
||||
return store.getters['workspace/workspacesById'][workspaceId];
|
||||
},
|
||||
getChanges() {
|
||||
|
@ -118,6 +118,8 @@ export default {
|
||||
const token = {
|
||||
accessToken,
|
||||
name: user.username,
|
||||
applicationId,
|
||||
applicationSecret,
|
||||
refreshToken: tokenBody.refresh_token,
|
||||
expiresOn: Date.now() + (tokenBody.expires_in * 1000),
|
||||
serverUrl,
|
||||
|
@ -7,6 +7,8 @@ import constants from '../../../data/constants';
|
||||
|
||||
const tokenExpirationMargin = 5 * 60 * 1000;
|
||||
|
||||
const appDataRepo = 'stackedit-app-data';
|
||||
|
||||
const request = (token, options) => networkSvc.request({
|
||||
...options,
|
||||
headers: {
|
||||
@ -44,6 +46,9 @@ userSvc.setInfoResolver('gitee', subPrefix, async (sub) => {
|
||||
},
|
||||
})).body;
|
||||
|
||||
if (user.avatar_url && user.avatar_url.endsWith('.png')) {
|
||||
user.avatar_url = `${user.avatar_url}!avatar60`;
|
||||
}
|
||||
return {
|
||||
id: `${subPrefix}:${user.login}`,
|
||||
name: user.login,
|
||||
@ -63,7 +68,7 @@ export default {
|
||||
/**
|
||||
* https://developer.gitee.com/apps/building-oauth-apps/authorization-options-for-oauth-apps/
|
||||
*/
|
||||
async startOauth2(lastRefreshToken, silent = false) {
|
||||
async startOauth2(lastToken, silent = false, isMain) {
|
||||
const clientId = store.getters['data/serverConf'].giteeClientId;
|
||||
let tokenBody;
|
||||
if (!silent) {
|
||||
@ -94,7 +99,7 @@ export default {
|
||||
url: 'https://gitee.com/oauth/token',
|
||||
params: {
|
||||
grant_type: 'refresh_token',
|
||||
refresh_token: lastRefreshToken,
|
||||
refresh_token: lastToken.refreshToken,
|
||||
},
|
||||
})).body;
|
||||
}
|
||||
@ -107,21 +112,32 @@ export default {
|
||||
access_token: accessToken,
|
||||
},
|
||||
})).body;
|
||||
if (user.avatar_url && user.avatar_url.endsWith('.png')) {
|
||||
user.avatar_url = `${user.avatar_url}!avatar60`;
|
||||
}
|
||||
userSvc.addUserInfo({
|
||||
id: `${subPrefix}:${user.login}`,
|
||||
name: user.login,
|
||||
imageUrl: user.avatar_url || '',
|
||||
});
|
||||
|
||||
// 获取同一个用户的登录token
|
||||
const existingToken = store.getters['data/giteeTokensBySub'][user.login];
|
||||
|
||||
// Build token object including sub 在token失效后刷新token 如果刷新失败则触发重新授权
|
||||
const token = {
|
||||
accessToken,
|
||||
// 主文档空间的登录 标识登录
|
||||
isLogin: !!isMain || (existingToken && !!existingToken.isLogin),
|
||||
refreshToken: tokenBody.refresh_token,
|
||||
expiresOn: Date.now() + (tokenBody.expires_in * 1000),
|
||||
name: user.login,
|
||||
sub: `${user.login}`,
|
||||
};
|
||||
|
||||
if (isMain) {
|
||||
// 检查 stackedit-app-data 仓库是否已经存在 如果不存在则创建该仓库
|
||||
await this.checkAndCreateRepo(token);
|
||||
}
|
||||
// Add token to gitee tokens
|
||||
store.dispatch('data/addGiteeToken', token);
|
||||
return token;
|
||||
@ -146,7 +162,7 @@ export default {
|
||||
// existing token is about to expire.
|
||||
// Try to get a new token in background
|
||||
try {
|
||||
return await this.startOauth2(lastToken.refreshToken, true);
|
||||
return await this.startOauth2(lastToken, true);
|
||||
} catch (err) {
|
||||
// If it fails try to popup a window
|
||||
if (store.state.offline) {
|
||||
@ -159,6 +175,9 @@ export default {
|
||||
return this.startOauth2();
|
||||
}
|
||||
},
|
||||
signin() {
|
||||
return this.startOauth2(null, false, true);
|
||||
},
|
||||
async addAccount() {
|
||||
const token = await this.startOauth2();
|
||||
badgeSvc.addBadge('addGiteeAccount');
|
||||
@ -188,6 +207,27 @@ export default {
|
||||
return tree;
|
||||
},
|
||||
|
||||
async checkAndCreateRepo(token) {
|
||||
const url = `https://gitee.com/api/v5/repos/${encodeURIComponent(token.name)}/${encodeURIComponent(appDataRepo)}`;
|
||||
try {
|
||||
await request(token, { url });
|
||||
} catch (err) {
|
||||
// 不存在则创建
|
||||
if (err.status === 404) {
|
||||
await request(token, {
|
||||
method: 'POST',
|
||||
url: 'https://gitee.com/api/v5/user/repos',
|
||||
params: {
|
||||
name: appDataRepo,
|
||||
auto_init: true,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* https://developer.gitee.com/v3/repos/commits/#list-commits-on-a-repository
|
||||
*/
|
||||
|
@ -4,7 +4,7 @@ import utils from './utils';
|
||||
import diffUtils from './diffUtils';
|
||||
import networkSvc from './networkSvc';
|
||||
import providerRegistry from './providers/common/providerRegistry';
|
||||
import googleDriveAppDataProvider from './providers/googleDriveAppDataProvider';
|
||||
import giteeAppDataProvider from './providers/giteeAppDataProvider';
|
||||
import './providers/couchdbWorkspaceProvider';
|
||||
import './providers/githubWorkspaceProvider';
|
||||
import './providers/giteeWorkspaceProvider';
|
||||
@ -821,7 +821,7 @@ const requestSync = (addTriggerSyncBadge = false) => {
|
||||
clearInterval(intervalId);
|
||||
if (!isSyncPossible()) {
|
||||
// Cancel sync
|
||||
throw new Error('Sync not possible.');
|
||||
throw new Error('无法同步。');
|
||||
}
|
||||
|
||||
// Determine if we have to clean files
|
||||
@ -888,7 +888,7 @@ export default {
|
||||
// Try to find a suitable workspace sync provider
|
||||
workspaceProvider = providerRegistry.providersById[utils.queryParams.providerId];
|
||||
if (!workspaceProvider || !workspaceProvider.initWorkspace) {
|
||||
workspaceProvider = googleDriveAppDataProvider;
|
||||
workspaceProvider = giteeAppDataProvider;
|
||||
}
|
||||
const workspace = await workspaceProvider.initWorkspace();
|
||||
// Fix the URL hash
|
||||
@ -938,7 +938,7 @@ export default {
|
||||
|
||||
// Unload contents from memory periodically
|
||||
utils.setInterval(() => {
|
||||
// Wait for sync and publish to finish
|
||||
// Wait for sync and 发布到finish
|
||||
if (store.state.queue.isEmpty) {
|
||||
localDbSvc.unloadContents();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import utils from '../services/utils';
|
||||
import googleHelper from '../services/providers/helpers/googleHelper';
|
||||
import giteeHelper from '../services/providers/helpers/giteeHelper';
|
||||
import syncSvc from '../services/syncSvc';
|
||||
|
||||
const idShifter = offset => (state, getters) => {
|
||||
@ -137,7 +137,7 @@ export default {
|
||||
if (!loginToken) {
|
||||
try {
|
||||
await dispatch('modal/open', 'signInForComment', { root: true });
|
||||
await googleHelper.signin();
|
||||
await giteeHelper.signin();
|
||||
syncSvc.requestSync();
|
||||
await dispatch('createNewDiscussion', selection);
|
||||
} catch (e) { /* cancel */ }
|
||||
|
@ -22,7 +22,7 @@ export default {
|
||||
Object.entries(rootGetters['data/workspaces']).forEach(([id, workspace]) => {
|
||||
const sanitizedWorkspace = {
|
||||
id,
|
||||
providerId: 'googleDriveAppData',
|
||||
providerId: 'giteeAppData',
|
||||
sub: mainWorkspaceToken && mainWorkspaceToken.sub,
|
||||
...workspace,
|
||||
};
|
||||
@ -46,16 +46,18 @@ export default {
|
||||
currentWorkspace.providerId === 'githubWorkspace'
|
||||
|| currentWorkspace.providerId === 'giteeWorkspace'
|
||||
|| currentWorkspace.providerId === 'gitlabWorkspace'
|
||||
|| currentWorkspace.providerId === 'giteaWorkspace',
|
||||
|| currentWorkspace.providerId === 'giteaWorkspace'
|
||||
|| currentWorkspace.providerId === 'giteeAppData',
|
||||
currentWorkspaceHasUniquePaths: (state, { currentWorkspace }) =>
|
||||
currentWorkspace.providerId === 'githubWorkspace'
|
||||
|| currentWorkspace.providerId === 'giteeWorkspace'
|
||||
|| currentWorkspace.providerId === 'gitlabWorkspace'
|
||||
|| currentWorkspace.providerId === 'giteaWorkspace',
|
||||
|| currentWorkspace.providerId === 'giteaWorkspace'
|
||||
|| currentWorkspace.providerId === 'giteeAppData',
|
||||
lastSyncActivityKey: (state, { currentWorkspace }) => `${currentWorkspace.id}/lastSyncActivity`,
|
||||
lastFocusKey: (state, { currentWorkspace }) => `${currentWorkspace.id}/lastWindowFocus`,
|
||||
mainWorkspaceToken: (state, getters, rootState, rootGetters) =>
|
||||
utils.someResult(Object.values(rootGetters['data/googleTokensBySub']), (token) => {
|
||||
utils.someResult(Object.values(rootGetters['data/giteeTokensBySub']), (token) => {
|
||||
if (token.isLogin) {
|
||||
return token;
|
||||
}
|
||||
@ -82,11 +84,11 @@ export default {
|
||||
loginType: (state, { currentWorkspace }) => {
|
||||
switch (currentWorkspace.providerId) {
|
||||
case 'googleDriveWorkspace':
|
||||
default:
|
||||
return 'google';
|
||||
case 'githubWorkspace':
|
||||
return 'github';
|
||||
case 'giteeWorkspace':
|
||||
default:
|
||||
return 'gitee';
|
||||
case 'gitlabWorkspace':
|
||||
return 'gitlab';
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
<head>
|
||||
<title>StackEdit中文版 – 浏览器内 Markdown 编辑器</title>
|
||||
<link rel="canonical" href="https://edit.qicoder.com/">
|
||||
<link rel="canonical" href="https://stackedit.cn/">
|
||||
<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">
|
||||
@ -13,7 +13,7 @@
|
||||
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="msvalidate.01" content="5E47EE6F67B069C17E3CDD418351A612">
|
||||
<meta name="google-site-verification" content="iWDn0T2r2_bDQWp_nW23MGePbO9X0M8wQSzbOU70pFQ" />
|
||||
<link rel="stylesheet" href="https://edit.qicoder.com/style.css">
|
||||
<link rel="stylesheet" href="https://stackedit.cn/style.css">
|
||||
<style>
|
||||
body {
|
||||
background-color: #fbfbfb;
|
||||
@ -353,7 +353,7 @@
|
||||
<div class="column">
|
||||
<div class="feature">
|
||||
<h3>协作</h3>
|
||||
<p>借助 StackEdit,您可以共享协作工作空间,这要归功于同步机制。 如果两个协作者同时处理同一个文件,StackEdit 会负责合并更改。</p>
|
||||
<p>借助 StackEdit,您可以共享协作文档空间,这要归功于同步机制。 如果两个协作者同时处理同一个文件,StackEdit 会负责合并更改。</p>
|
||||
</div>
|
||||
<img class="image" width="300" src="static/landing/workspace.png">
|
||||
</div>
|
||||
@ -450,7 +450,7 @@
|
||||
</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>
|
||||
Copyright 2013-2022 <a href="https://gitee.com/mafgwo" target="_blank">豆萁</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 href="privacy_policy.html" target="_blank">隐私策略</a>
|
||||
|
90
static/landing/privacy_policy.html
Normal file
90
static/landing/privacy_policy.html
Normal file
@ -0,0 +1,90 @@
|
||||
<!DOCTYPE html>
|
||||
<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;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.date-text {
|
||||
text-align: right;
|
||||
padding-right: 20px;
|
||||
color: #333;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 10px 10px 20px;
|
||||
}
|
||||
|
||||
.main-text {
|
||||
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">
|
||||
【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>
|
@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://edit.qicoder.com/</loc>
|
||||
<loc>https://stackedit.cn/</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://edit.qicoder.com/app</loc>
|
||||
<loc>https://stackedit.cn/app</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
@ -16,7 +16,7 @@
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://edit.qicoder.com/privacy_policy.html</loc>
|
||||
<loc>https://stackedit.cn/privacy_policy.html</loc>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
|
Loading…
Reference in New Issue
Block a user