From 169b99a358f166185147970b916adf1a09d23de3 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 15 Dec 2017 06:41:57 +0900
Subject: [PATCH] :v:

---
 gulpfile.ts                         | 19 +-------
 src/web/docs/api/endpoints/view.pug |  3 +-
 src/web/docs/api/entities/view.pug  |  2 +-
 src/web/docs/api/gulpfile.ts        | 60 ++++++++++++++++---------
 src/web/docs/api/mixins.pug         |  6 +--
 src/web/docs/gulpfile.ts            | 64 ++++++++++++++++++++++++++
 src/web/docs/index.en.pug           |  9 ++++
 src/web/docs/index.ja.pug           |  9 ++++
 src/web/docs/index.md               |  4 --
 src/web/docs/layout.pug             | 23 +++++++---
 src/web/docs/style.styl             | 69 ++++++++++++++++-------------
 src/web/docs/vars.ts                | 36 +++++++++++++++
 12 files changed, 220 insertions(+), 84 deletions(-)
 create mode 100644 src/web/docs/gulpfile.ts
 create mode 100644 src/web/docs/index.en.pug
 create mode 100644 src/web/docs/index.ja.pug
 delete mode 100644 src/web/docs/index.md
 create mode 100644 src/web/docs/vars.ts

diff --git a/gulpfile.ts b/gulpfile.ts
index 6807b6d571..e7d4770610 100644
--- a/gulpfile.ts
+++ b/gulpfile.ts
@@ -13,7 +13,6 @@ import * as es from 'event-stream';
 import cssnano = require('gulp-cssnano');
 import * as uglifyComposer from 'gulp-uglify/composer';
 import pug = require('gulp-pug');
-import stylus = require('gulp-stylus');
 import * as rimraf from 'rimraf';
 import chalk from 'chalk';
 import imagemin = require('gulp-imagemin');
@@ -48,32 +47,18 @@ if (isDebug) {
 
 const constants = require('./src/const.json');
 
-require('./src/web/docs/api/gulpfile.ts');
+require('./src/web/docs/gulpfile.ts');
 
 gulp.task('build', [
 	'build:js',
 	'build:ts',
 	'build:copy',
 	'build:client',
-	'build:doc'
+	'doc'
 ]);
 
 gulp.task('rebuild', ['clean', 'build']);
 
-gulp.task('build:doc', [
-	'doc:api',
-	'doc:styles'
-]);
-
-gulp.task('doc:styles', () =>
-	gulp.src('./src/web/docs/**/*.styl')
-		.pipe(stylus())
-		.pipe(isProduction
-			? (cssnano as any)()
-			: gutil.noop())
-		.pipe(gulp.dest('./built/web/assets/docs/'))
-);
-
 gulp.task('build:js', () =>
 	gulp.src(['./src/**/*.js', '!./src/web/**/*.js'])
 		.pipe(gulp.dest('./built/'))
diff --git a/src/web/docs/api/endpoints/view.pug b/src/web/docs/api/endpoints/view.pug
index cebef9fa5b..cab814cabc 100644
--- a/src/web/docs/api/endpoints/view.pug
+++ b/src/web/docs/api/endpoints/view.pug
@@ -12,7 +12,7 @@ block main
 
 	p#url= url
 
-	p#desc: +i18n(desc)
+	p#desc= desc[lang] || desc['ja']
 
 	section
 		h2 Params
@@ -27,4 +27,3 @@ block main
 	section
 		h2 Response
 		+propTable(res)
-
diff --git a/src/web/docs/api/entities/view.pug b/src/web/docs/api/entities/view.pug
index f210582f1a..756e966b53 100644
--- a/src/web/docs/api/entities/view.pug
+++ b/src/web/docs/api/entities/view.pug
@@ -10,7 +10,7 @@ block meta
 block main
 	h1= name
 
-	p#desc: +i18n(desc)
+	p#desc= desc[lang] || desc['ja']
 
 	section
 		h2 Properties
diff --git a/src/web/docs/api/gulpfile.ts b/src/web/docs/api/gulpfile.ts
index 6453996d31..6cbae5ea2d 100644
--- a/src/web/docs/api/gulpfile.ts
+++ b/src/web/docs/api/gulpfile.ts
@@ -12,6 +12,12 @@ import * as mkdirp from 'mkdirp';
 
 import config from './../../../conf';
 
+import generateVars from '../vars';
+
+const commonVars = generateVars();
+
+const langs = ['ja', 'en'];
+
 const kebab = string => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase();
 
 const parseParam = param => {
@@ -102,20 +108,25 @@ gulp.task('doc:api:endpoints', () => {
 				paramDefs: extractDefs(ep.params),
 				res: sortParams(ep.res.map(p => parseParam(p))),
 				resDefs: extractDefs(ep.res),
-				kebab
+				kebab,
+				common: commonVars
 			};
-			pug.renderFile('./src/web/docs/api/endpoints/view.pug', vars, (renderErr, html) => {
-				if (renderErr) {
-					console.error(renderErr);
-					return;
-				}
-				const htmlPath = `./built/web/docs/api/endpoints/${ep.endpoint}.html`;
-				mkdirp(path.dirname(htmlPath), (mkdirErr) => {
-					if (mkdirErr) {
-						console.error(mkdirErr);
+			langs.forEach(lang => {
+				pug.renderFile('./src/web/docs/api/endpoints/view.pug', Object.assign({}, vars, {
+					lang
+				}), (renderErr, html) => {
+					if (renderErr) {
+						console.error(renderErr);
 						return;
 					}
-					fs.writeFileSync(htmlPath, html, 'utf-8');
+					const htmlPath = `./built/web/docs/${lang}/api/endpoints/${ep.endpoint}.html`;
+					mkdirp(path.dirname(htmlPath), (mkdirErr) => {
+						if (mkdirErr) {
+							console.error(mkdirErr);
+							return;
+						}
+						fs.writeFileSync(htmlPath, html, 'utf-8');
+					});
 				});
 			});
 		});
@@ -135,20 +146,25 @@ gulp.task('doc:api:entities', () => {
 				desc: entity.desc,
 				props: sortParams(entity.props.map(p => parseParam(p))),
 				propDefs: extractDefs(entity.props),
-				kebab
+				kebab,
+				common: commonVars
 			};
-			pug.renderFile('./src/web/docs/api/entities/view.pug', vars, (renderErr, html) => {
-				if (renderErr) {
-					console.error(renderErr);
-					return;
-				}
-				const htmlPath = `./built/web/docs/api/entities/${kebab(entity.name)}.html`;
-				mkdirp(path.dirname(htmlPath), (mkdirErr) => {
-					if (mkdirErr) {
-						console.error(mkdirErr);
+			langs.forEach(lang => {
+				pug.renderFile('./src/web/docs/api/entities/view.pug', Object.assign({}, vars, {
+					lang
+				}), (renderErr, html) => {
+					if (renderErr) {
+						console.error(renderErr);
 						return;
 					}
-					fs.writeFileSync(htmlPath, html, 'utf-8');
+					const htmlPath = `./built/web/docs/${lang}/api/entities/${kebab(entity.name)}.html`;
+					mkdirp(path.dirname(htmlPath), (mkdirErr) => {
+						if (mkdirErr) {
+							console.error(mkdirErr);
+							return;
+						}
+						fs.writeFileSync(htmlPath, html, 'utf-8');
+					});
 				});
 			});
 		});
diff --git a/src/web/docs/api/mixins.pug b/src/web/docs/api/mixins.pug
index b302c78263..3ddd7cb48a 100644
--- a/src/web/docs/api/mixins.pug
+++ b/src/web/docs/api/mixins.pug
@@ -14,13 +14,13 @@ mixin propTable(props)
 						if prop.kind == 'id'
 							if prop.entity
 								|  (
-								a(href=`/docs/api/entities/${kebab(prop.entity)}`)= prop.entity
+								a(href=`/docs/${lang}/api/entities/${kebab(prop.entity)}`)= prop.entity
 								|  ID)
 							else
 								|  (ID)
 						else if prop.kind == 'entity'
 							|   (
-							a(href=`/docs/api/entities/${kebab(prop.entity)}`)= prop.entity
+							a(href=`/docs/${lang}/api/entities/${kebab(prop.entity)}`)= prop.entity
 							| )
 						else if prop.kind == 'object'
 							if prop.def
@@ -30,4 +30,4 @@ mixin propTable(props)
 						else if prop.kind == 'date'
 							|  (Date)
 					td.optional= prop.optional.toString()
-					td.desc: +i18n(prop.desc)
+					td.desc!= prop.desc[lang] || prop.desc['ja']
diff --git a/src/web/docs/gulpfile.ts b/src/web/docs/gulpfile.ts
new file mode 100644
index 0000000000..6f2351dacb
--- /dev/null
+++ b/src/web/docs/gulpfile.ts
@@ -0,0 +1,64 @@
+/**
+ * Gulp tasks
+ */
+
+import * as fs from 'fs';
+import * as path from 'path';
+import * as glob from 'glob';
+import * as gulp from 'gulp';
+import * as pug from 'pug';
+//import * as yaml from 'js-yaml';
+import * as mkdirp from 'mkdirp';
+import stylus = require('gulp-stylus');
+import cssnano = require('gulp-cssnano');
+
+//import config from './../../conf';
+
+import generateVars from './vars';
+
+require('./api/gulpfile.ts');
+
+gulp.task('doc', [
+	'doc:docs',
+	'doc:api',
+	'doc:styles'
+]);
+
+const commonVars = generateVars();
+
+gulp.task('doc:docs', () => {
+	glob('./src/web/docs/**/*.*.pug', (globErr, files) => {
+		if (globErr) {
+			console.error(globErr);
+			return;
+		}
+		files.forEach(file => {
+			const [, name, lang] = file.match(/docs\/(.+?)\.(.+?)\.pug$/);
+			const vars = {
+				common: commonVars,
+				lang: lang
+			};
+			pug.renderFile(file, vars, (renderErr, html) => {
+				if (renderErr) {
+					console.error(renderErr);
+					return;
+				}
+				const htmlPath = `./built/web/docs/${lang}/${name}.html`;
+				mkdirp(path.dirname(htmlPath), (mkdirErr) => {
+					if (mkdirErr) {
+						console.error(mkdirErr);
+						return;
+					}
+					fs.writeFileSync(htmlPath, html, 'utf-8');
+				});
+			});
+		});
+	});
+});
+
+gulp.task('doc:styles', () =>
+	gulp.src('./src/web/docs/**/*.styl')
+		.pipe(stylus())
+		.pipe((cssnano as any)())
+		.pipe(gulp.dest('./built/web/assets/docs/'))
+);
diff --git a/src/web/docs/index.en.pug b/src/web/docs/index.en.pug
new file mode 100644
index 0000000000..af0bba8b2c
--- /dev/null
+++ b/src/web/docs/index.en.pug
@@ -0,0 +1,9 @@
+extends ./layout.pug
+
+block title
+	| Misskey Docs
+
+block main
+	h1 Misskey Docs
+
+	p Welcome to docs of Misskey.
diff --git a/src/web/docs/index.ja.pug b/src/web/docs/index.ja.pug
new file mode 100644
index 0000000000..cd43045f6e
--- /dev/null
+++ b/src/web/docs/index.ja.pug
@@ -0,0 +1,9 @@
+extends ./layout.pug
+
+block title
+	| Misskey ドキュメント
+
+block main
+	h1 Misskey ドキュメント
+
+	p Misskeyのドキュメントへようこそ
diff --git a/src/web/docs/index.md b/src/web/docs/index.md
deleted file mode 100644
index 0846cf27e8..0000000000
--- a/src/web/docs/index.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Misskeyについて
-================================================================
-
-誰か書いて
diff --git a/src/web/docs/layout.pug b/src/web/docs/layout.pug
index 68ca9eb62d..d6ecb4b6aa 100644
--- a/src/web/docs/layout.pug
+++ b/src/web/docs/layout.pug
@@ -1,16 +1,29 @@
 doctype html
 
-mixin i18n(xs)
-	each text, lang in xs
-		span(class=`i18n ${lang}`)!= text
-
-html
+html(lang= lang)
 	head
 		meta(charset="UTF-8")
+		meta(name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no")
 		title
 			block title
+		link(rel="stylesheet" href="/assets/docs/style.css")
 		block meta
 
 	body
+		nav
+			ul
+				each doc in common.docs
+					li: a(href=`/docs/${lang}/${doc.name}`)= doc.title[lang] || doc.title['ja']
+			section
+				h2 API
+				ul
+					li Entities
+						ul
+							each entity in common.entities
+								li: a(href=`/docs/${lang}/api/entities/${common.kebab(entity)}`)= entity
+					li Endpoints
+						ul
+							each endpoint in common.endpoints
+								li: a(href=`/docs/${lang}/api/endpoints/${common.kebab(endpoint)}`)= endpoint
 		main
 			block main
diff --git a/src/web/docs/style.styl b/src/web/docs/style.styl
index a4abc5a9a3..2e2f9f5743 100644
--- a/src/web/docs/style.styl
+++ b/src/web/docs/style.styl
@@ -5,10 +5,49 @@ body
 	color #34495e
 
 main
+	margin 0 0 0 256px
 	padding 32px
 	width 100%
 	max-width 700px
 
+	section
+		margin 32px 0
+
+	h1
+		margin 0 0 24px 0
+		padding 16px 0
+		font-size 1.5em
+		border-bottom solid 2px #eee
+
+	h2
+		margin 0 0 24px 0
+		padding 0 0 16px 0
+		font-size 1.4em
+		border-bottom solid 1px #eee
+
+	h3
+		margin 0
+		padding 0
+		font-size 1.25em
+
+	h4
+		margin 0
+
+	p
+		margin 1em 0
+		line-height 1.6em
+
+nav
+	display block
+	position fixed
+	top 0
+	left 0
+	width 256px
+	height 100%
+	overflow auto
+	padding 32px
+	border-right solid 2px #eee
+
 footer
 	padding:32px 0 0 0
 	margin 32px 0 0 0
@@ -18,33 +57,6 @@ footer
 		margin 16px 0 0 0
 		color #aaa
 
-section
-	margin 32px 0
-
-h1
-	margin 0 0 24px 0
-	padding 16px 0
-	font-size 1.5em
-	border-bottom solid 2px #eee
-
-h2
-	margin 0 0 24px 0
-	padding 0 0 16px 0
-	font-size 1.4em
-	border-bottom solid 1px #eee
-
-h3
-	margin 0
-	padding 0
-	font-size 1.25em
-
-h4
-	margin 0
-
-p
-	margin 1em 0
-	line-height 1.6em
-
 table
 	width 100%
 	border-spacing 0
@@ -72,6 +84,3 @@ table
 
 	th, td
 		padding 8px 16px
-
-.i18n:not(.ja)
-	display none
diff --git a/src/web/docs/vars.ts b/src/web/docs/vars.ts
new file mode 100644
index 0000000000..ed2149df4a
--- /dev/null
+++ b/src/web/docs/vars.ts
@@ -0,0 +1,36 @@
+import * as fs from 'fs';
+import * as glob from 'glob';
+import * as yaml from 'js-yaml';
+
+export default function() {
+	const vars = {};
+
+	const endpoints = glob.sync('./src/web/docs/api/endpoints/**/*.yaml');
+	vars['endpoints'] = endpoints.map(ep => {
+		const _ep = yaml.safeLoad(fs.readFileSync(ep, 'utf-8'));
+		return _ep.endpoint;
+	});
+
+	const entities = glob.sync('./src/web/docs/api/entities/**/*.yaml');
+	vars['entities'] = entities.map(x => {
+		const _x = yaml.safeLoad(fs.readFileSync(x, 'utf-8'));
+		return _x.name;
+	});
+
+	const docs = glob.sync('./src/web/docs/**/*.*.pug');
+	vars['docs'] = {};
+	docs.forEach(x => {
+		const [, name, lang] = x.match(/docs\/(.+?)\.(.+?)\.pug$/);
+		if (vars['docs'][name] == null) {
+			vars['docs'][name] = {
+				name,
+				title: {}
+			};
+		}
+		vars['docs'][name]['title'][lang] = fs.readFileSync(x, 'utf-8').match(/\r\n\th1 (.+?)\r\n/)[1];
+	});
+
+	vars['kebab'] = string => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase();
+
+	return vars;
+}