!2 合并到master

Merge pull request !2 from 豆萁/zh
This commit is contained in:
豆萁 2022-06-07 06:48:55 +00:00 committed by Gitee
commit f489a611b0
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
100 changed files with 1382 additions and 1028 deletions

View File

@ -1,4 +1,4 @@
FROM node:11.15.0
FROM mafgwo/wkhtmltopdf-nodejs:11.15.0
RUN mkdir -p /opt/stackedit
WORKDIR /opt/stackedit

View File

@ -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**
**已完成修改主文档空间为Gitee2022-06-04**
对应Docker版本5.15.6, tag: v5.15.6
### 目前已部署地址
https://edit.qicoder.com/
https://stackedit.cn/
该地址可以作为试用或长期使用本人承诺绝对没采集任何人的Token等敏感信息不需要担心私有仓库泄漏。

View File

@ -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,

View File

@ -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">

View File

@ -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",

View File

@ -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

View File

@ -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.');
}
});
};

View File

@ -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.');
}
});
};

View File

@ -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>

View File

@ -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">

View File

@ -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) {

View File

@ -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">

View File

@ -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>

View File

@ -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 {

View File

@ -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', [

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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>转换为PDFWordEPUB...</span>
</menu-entry>
</menu-entry> -->
</div>
</template>

View File

@ -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

View File

@ -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">

View File

@ -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">

View File

@ -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>

View File

@ -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>

View File

@ -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">

View File

@ -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>

View File

@ -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">&mdash; {{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>

View File

@ -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">将信息添加到您的发布WordPressBlogger ...</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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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);
}
});
},

View File

@ -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);
}
});
},

View File

@ -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>

View File

@ -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: {

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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');

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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: |

View File

@ -1,7 +1,7 @@
export default () => ({
main: {
id: 'main',
name: '主工作区',
name: '主文档空间',
// The rest will be filled by the workspace/workspacesById getter
},
});

View File

@ -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是一个基于浏览器的应用程序。GiteeGithubDropbox ...发出的访问令牌存储在您的浏览器中,不会发送到任何形式的后端或第三方,因此任何人都不会访问您的数据。

View File

@ -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模板。',
),
],
),

View File

@ -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>',
'取消',
'确认授权',
),
};

View File

@ -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}}

View File

@ -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}}

View File

@ -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 会将您的文件链接到该发布,这使您可以轻松地重新发布它。一旦您修改了文件并想要更新您的发布,请单击导航栏中的**立即发布**按钮。
> **注意:** 如果您的文件尚未发布,则 **立即发布** 按钮将被禁用。

View File

@ -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:

View 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);
},
});

View File

@ -87,7 +87,7 @@ export default new Provider({
});
}
badgeSvc.addBadge('addGithubWorkspace');
badgeSvc.addBadge('addGiteeWorkspace');
return store.getters['workspace/workspacesById'][workspaceId];
},
getChanges() {

View File

@ -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,

View File

@ -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
*/

View File

@ -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();
}

View File

@ -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 */ }

View File

@ -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';

View File

@ -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>

View 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>

View File

@ -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>