diff --git a/gulpfile.ts b/gulpfile.ts index 9586ed36a..53d627066 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -3,13 +3,11 @@ */ import * as childProcess from 'child_process'; -import * as fs from 'fs'; import * as Path from 'path'; import * as gulp from 'gulp'; import * as gutil from 'gulp-util'; import * as ts from 'gulp-typescript'; import tslint from 'gulp-tslint'; -import * as glob from 'glob'; import * as es from 'event-stream'; import cssnano = require('gulp-cssnano'); import * as uglify from 'gulp-uglify'; @@ -36,7 +34,6 @@ const constants = require('./src/const.json'); gulp.task('build', [ 'build:js', 'build:ts', - 'build:about:docs', 'build:copy', 'build:client' ]); @@ -57,31 +54,6 @@ gulp.task('build:ts', () => { .pipe(gulp.dest('./built/')); }); -gulp.task('build:about:docs', () => { - function getLicenseHtml(path: string) { - return fs.readFileSync(path, 'utf-8') - .replace(/\r\n/g, '\n') - .replace(/(.)\n(.)/g, '$1 $2') - .replace(/(^|\n)(.*?)($|\n)/g, '
$2
'); - } - - const licenseHtml = getLicenseHtml('./LICENSE'); - const streams = glob.sync('./docs/**/*.pug').map(file => { - const page = file.replace('./docs/', '').replace('.pug', ''); - return gulp.src(file) - .pipe(pug({ - locals: { - path: page, - license: licenseHtml, - themeColor: constants.themeColor - } - })) - .pipe(gulp.dest('./built/web/about/pages/' + Path.parse(page).dir)); - }); - - return es.merge.apply(es, streams); -}); - gulp.task('build:copy', () => es.merge( gulp.src([ @@ -141,7 +113,7 @@ gulp.task('webpack', done => { }); gulp.task('build:client:script', () => - gulp.src('./src/web/app/client/script.js') + gulp.src('./src/web/app/boot.js') .pipe(replace('VERSION', JSON.stringify(version))) .pipe(isProduction ? uglify() : gutil.noop()) .pipe(gulp.dest('./built/web/assets/client/')) as any diff --git a/src/web/about/assets/style.css b/src/web/about/assets/style.css deleted file mode 100644 index 028bffa52..000000000 --- a/src/web/about/assets/style.css +++ /dev/null @@ -1,208 +0,0 @@ -html { - font-family: sans-serif; -} - -body { - margin: 0; - color: #34495e; -} - -nav { - display: block; - float: left; - width: 210px; -} -nav ul { - display: block; - margin: 0 0 16px 0; - padding: 0 0 0 16px; - list-style: none; -} -nav ul li { - margin: 0; - padding: 0; -} -nav ul li p { - margin: 16px 0 0 0; -} -@media screen and (max-width: 910px) { - nav { - display: none; - } -} - -main { - float: left; - box-sizing: border-box; - padding: 32px; - width: 100%; - max-width: 700px; - overflow-wrap: break-word; -} -@media screen and (max-width: 700px) { - main { - font-size: 8px; - } -} - -footer { - padding: 32px 0 0 0; - margin: 32px 0 0 0; - border-top: solid 1px #eee; -} - -footer .contribution { - margin: 0 0 16px 0; -} - -footer .copyright { - margin: 16px 0 0 0; - color: #aaa; -} - -a { - text-decoration: none; - color: #f76d6c; -} - a:hover { - text-decoration: underline; - } - -hr { - border-top: solid 1px #eee; -} - -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; -} - -p.tip { - position: relative; - padding: 12px 24px 12px 30px; - margin: 1em 0; - font-size: 0.9em; - border-left: 4px solid #f66; - background-color: #f8f8f8; - border-bottom-right-radius: 2px; - border-top-right-radius: 2px; -} - p.tip:before { - position: absolute; - top: 14px; - left: -12px; - background-color: #f66; - color: #fff; - content: "!"; - width: 20px; - height: 20px; - border-radius: 100%; - text-align: center; - line-height: 20px; - font-weight: bold; - font-family: 'Dosis', 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif; - font-size: 14px; - } - -hr { - margin: 1em 0; -} - -table { - width: 100%; - border-spacing: 0; - border-collapse: collapse; -} - -table thead { - font-weight: bold; - border-bottom: solid 2px #eee; -} - -table tbody tr { - border-bottom: dashed 1px #eee; -} - -table th, table td { - padding: 8px 16px; -} - -table.entity tbody tr td:nth-child(1) { - font-family: Consolas, 'Courier New', Courier, Monaco, monospace; -} - -table.entity tbody tr td:nth-child(2) { - font-style: italic; -} - -table.entity tr td:nth-child(3):after { - margin-left: 8px; - opacity: 0.7; -} - -table.entity tr.nullable td:nth-child(2):after { - content: "?"; - opacity: 0.7; -} -table.entity tr.nullable td:nth-child(3):after { - content: "(Null許容)"; -} - -table.entity tr.optional { - opacity: 0.7; -} -table.entity tr.optional td:nth-child(3):after { - content: "(省略可能)"; -} - -table.entity tr.nullable.optional td:nth-child(3):after { - content: "(Null許容かつ省略可能)"; -} - -pre, code, var, samp, kbd { - font-family: Consolas, 'Courier New', Courier, Monaco, monospace; -} - -code { - display: inline-block; - margin: 0 4px; - padding: 0 8px; - color: #525252; - background: #f8f8f8; - border-radius: 2px; -} - -pre code { - display: block; - overflow: auto; - margin: 0; - padding: 32px; -} diff --git a/src/web/about/index.ts b/src/web/about/index.ts deleted file mode 100644 index 9fedeb627..000000000 --- a/src/web/about/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as express from 'express'; -import ms = require('ms'); - -const router = express.Router(); - -router.use('/@/about/assets', express.static(`${__dirname}/assets`, { - maxAge: ms('7 days') -})); - -router.get('/@/about/', (req, res) => { - res.sendFile(`${__dirname}/pages/index.html`); -}); - -router.get('/@/about/:page(*)', (req, res) => { - res.sendFile(`${__dirname}/pages/${req.params.page}.html`); -}); - -module.exports = router; diff --git a/src/web/app/auth/script.js b/src/web/app/auth/script.js index 19391b2b9..fe7f9befe 100644 --- a/src/web/app/auth/script.js +++ b/src/web/app/auth/script.js @@ -7,14 +7,14 @@ import './style.styl'; import * as riot from 'riot'; require('./tags'); -import boot from '../boot'; +import init from '../init'; document.title = 'Misskey | アプリの連携'; /** - * Boot + * init */ -boot(me => { +init(me => { mount(document.createElement('mk-index')); }); diff --git a/src/web/app/auth/view.pug b/src/web/app/auth/view.pug deleted file mode 100644 index afa1e408f..000000000 --- a/src/web/app/auth/view.pug +++ /dev/null @@ -1,5 +0,0 @@ -extends ../base - -block head - meta(name='viewport' content='width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no') - script(src=`/assets/auth.${version}.ja.js` async defer) diff --git a/src/web/app/base.pug b/src/web/app/base.pug index 912157a2e..fd57f5593 100644 --- a/src/web/app/base.pug +++ b/src/web/app/base.pug @@ -9,11 +9,15 @@ html meta(name='application-name' content='Misskey') meta(name='theme-color' content=themeColor) meta(name='referrer' content='origin') + title Misskey + style include ./../../../built/web/assets/init.css + script + include ./../../../built/web/assets/boot.js + script(src='https://use.fontawesome.com/22aba0df4f.js' async) - block head body noscript: p diff --git a/src/web/app/boot.js b/src/web/app/boot.js index 242df13c7..4df44ed79 100644 --- a/src/web/app/boot.js +++ b/src/web/app/boot.js @@ -1,186 +1,35 @@ /** - * boot loader + * MISSKEY ENTRY POINT */ -"use strict"; +const Url = new URL(location.href); -import * as riot from 'riot'; -import api from './common/scripts/api'; -import signout from './common/scripts/signout'; -import checkForUpdate from './common/scripts/check-for-update'; -import mixin from './common/mixins'; -import generateDefaultUserdata from './common/scripts/generate-default-userdata'; -import CONFIG from './common/scripts/config'; -require('./common/tags'); +let app = Url.host.split('.')[0]; -/** - * MISSKEY ENTRY POINT! - */ +// Detect user language +let lang = navigator.language.split('-')[0]; +if (!/^(en|ja)$/.test(lang)) lang = 'en'; -console.info(`Misskey v${VERSION}`); +// Detect user agent +const ua = navigator.userAgent.toLowerCase(); +const isMobile = /mobile|iphone|ipad|android/.test(ua); -document.domain = CONFIG.host; +const head = document.getElementsByTagName('head')[0]; -// Set global configuration -riot.mixin({ CONFIG }); - -// ↓ NodeList、HTMLCollection、FileList、DataTransferItemListで forEach を使えるようにする -if (NodeList.prototype.forEach === undefined) { - NodeList.prototype.forEach = Array.prototype.forEach; -} -if (HTMLCollection.prototype.forEach === undefined) { - HTMLCollection.prototype.forEach = Array.prototype.forEach; -} -if (FileList.prototype.forEach === undefined) { - FileList.prototype.forEach = Array.prototype.forEach; -} -if (window.DataTransferItemList && DataTransferItemList.prototype.forEach === undefined) { - DataTransferItemList.prototype.forEach = Array.prototype.forEach; +if (isMobile) { + const meta = document.createElement('meta'); + meta.setAttribute('name', 'viewport'); + meta.setAttribute('content', 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no'); + head.appendChild(meta); } -// iOSでプライベートモードだとlocalStorageが使えないので既存のメソッドを上書きする -try { - localStorage.setItem('kyoppie', 'yuppie'); -} catch (e) { - Storage.prototype.setItem = () => { }; // noop +if (app == 'misskey') { + app = isMobile ? 'mobile' : 'desktop'; } -// クライアントを更新すべきならする -if (localStorage.getItem('should-refresh') == 'true') { - localStorage.removeItem('should-refresh'); - location.reload(true); -} - -// 更新チェック -setTimeout(checkForUpdate, 3000); - -// ユーザーをフェッチしてコールバックする -export default callback => { - // Get cached account data - let cachedMe = JSON.parse(localStorage.getItem('me')); - - if (cachedMe) { - fetched(cachedMe); - - // 後から新鮮なデータをフェッチ - fetchme(cachedMe.token, freshData => { - Object.assign(cachedMe, freshData); - cachedMe.trigger('updated'); - }); - } else { - // Get token from cookie - const i = (document.cookie.match(/i=(!\w+)/) || [null, null])[1]; - - fetchme(i, fetched); - } - - // フェッチが完了したとき - function fetched(me) { - if (me) { - riot.observable(me); - - // この me オブジェクトを更新するメソッド - me.update = data => { - if (data) Object.assign(me, data); - me.trigger('updated'); - }; - - // ローカルストレージにキャッシュ - localStorage.setItem('me', JSON.stringify(me)); - - me.on('updated', () => { - // キャッシュ更新 - localStorage.setItem('me', JSON.stringify(me)); - }); - } - - // ミックスイン初期化 - mixin(me); - - // ローディング画面クリア - const ini = document.getElementById('ini'); - ini.parentNode.removeChild(ini); - - // アプリ基底要素マウント - const app = document.createElement('div'); - app.setAttribute('id', 'app'); - document.body.appendChild(app); - - try { - callback(me); - } catch (e) { - panic(e); - } - } -}; - -// ユーザーをフェッチしてコールバックする -function fetchme(token, cb) { - let me = null; - - // Return when not signed in - if (token == null) { - return done(); - } - - // Fetch user - fetch(`${CONFIG.apiUrl}/i`, { - method: 'POST', - body: JSON.stringify({ - i: token - }) - }).then(res => { // When success - // When failed to authenticate user - if (res.status !== 200) { - return signout(); - } - - res.json().then(i => { - me = i; - me.token = token; - - // initialize it if user data is empty - me.data ? done() : init(); - }); - }, () => { // When failure - // Display error screen - riot.mount(document.body.appendChild( - document.createElement('mk-error'))); - }); - - function done() { - if (cb) cb(me); - } - - // Initialize user data - function init() { - const data = generateDefaultUserdata(); - api(token, 'i/appdata/set', { - data - }).then(() => { - me.data = data; - done(); - }); - } -} - -// BSoD -function panic(e) { - console.error(e); - - // Display blue screen - document.body.innerHTML = - `お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。
-エラーコード: ${e.toString()}
-ブラウザ バージョン: ${navigator.userAgent}
-クライアント バージョン: ${VERSION}
-問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。
-Thank you for using Misskey.
-お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。
+エラーコード: ${e.toString()}
+ブラウザ バージョン: ${navigator.userAgent}
+クライアント バージョン: ${VERSION}
+問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。
+Thank you for using Misskey.
+