summaryrefslogtreecommitdiff
path: root/src/web
diff options
context:
space:
mode:
authorha-dai <contact@haradai.net>2017-11-02 13:58:47 +0900
committerha-dai <contact@haradai.net>2017-11-02 13:58:47 +0900
commit4e83106853e1da2ff7f5b3dabe23c3791c25f289 (patch)
tree1fb73d608bfe65ad9274477fc2b99822d36bf76f /src/web
parentMerge branch 'master' of https://github.com/syuilo/misskey (diff)
parentRefactor (diff)
downloadmisskey-4e83106853e1da2ff7f5b3dabe23c3791c25f289.tar.gz
misskey-4e83106853e1da2ff7f5b3dabe23c3791c25f289.tar.bz2
misskey-4e83106853e1da2ff7f5b3dabe23c3791c25f289.zip
Merge branch 'master' of https://github.com/syuilo/misskey
Diffstat (limited to 'src/web')
-rw-r--r--src/web/app/app.styl (renamed from src/web/app/base.styl)8
-rw-r--r--src/web/app/auth/style.styl3
-rw-r--r--src/web/app/ch/router.js32
-rw-r--r--src/web/app/ch/script.js18
-rw-r--r--src/web/app/ch/style.styl10
-rw-r--r--src/web/app/ch/tags/channel.tag403
-rw-r--r--src/web/app/ch/tags/header.tag20
-rw-r--r--src/web/app/ch/tags/index.js3
-rw-r--r--src/web/app/ch/tags/index.tag35
-rw-r--r--src/web/app/common/scripts/channel-stream.js16
-rw-r--r--src/web/app/common/scripts/config.js2
-rw-r--r--src/web/app/desktop/router.js22
-rw-r--r--src/web/app/desktop/style.styl3
-rw-r--r--src/web/app/desktop/tags/home-widgets/rss-reader.tag2
-rw-r--r--src/web/app/desktop/tags/index.js1
-rw-r--r--src/web/app/desktop/tags/notifications.tag6
-rw-r--r--src/web/app/desktop/tags/pages/selectdrive.tag159
-rw-r--r--src/web/app/desktop/tags/pages/user.tag2
-rw-r--r--src/web/app/desktop/tags/post-detail.tag8
-rw-r--r--src/web/app/desktop/tags/post-form.tag2
-rw-r--r--src/web/app/desktop/tags/sub-post-content.tag2
-rw-r--r--src/web/app/desktop/tags/timeline.tag10
-rw-r--r--src/web/app/desktop/tags/ui.tag32
-rw-r--r--src/web/app/dev/style.styl3
-rw-r--r--src/web/app/mobile/router.js5
-rw-r--r--src/web/app/mobile/style.styl3
-rw-r--r--src/web/app/mobile/tags/drive.tag16
-rw-r--r--src/web/app/mobile/tags/index.js3
-rw-r--r--src/web/app/mobile/tags/notifications.tag6
-rw-r--r--src/web/app/mobile/tags/page/drive.tag2
-rw-r--r--src/web/app/mobile/tags/page/notifications.tag14
-rw-r--r--src/web/app/mobile/tags/page/selectdrive.tag87
-rw-r--r--src/web/app/mobile/tags/post-detail.tag8
-rw-r--r--src/web/app/mobile/tags/post-form.tag2
-rw-r--r--src/web/app/mobile/tags/sub-post-content.tag2
-rw-r--r--src/web/app/mobile/tags/timeline.tag10
-rw-r--r--src/web/app/mobile/tags/ui-header.tag156
-rw-r--r--src/web/app/mobile/tags/ui-nav.tag170
-rw-r--r--src/web/app/mobile/tags/ui.tag369
-rw-r--r--src/web/app/reset.styl13
-rw-r--r--src/web/app/stats/style.styl3
-rw-r--r--src/web/app/status/style.styl3
42 files changed, 1278 insertions, 396 deletions
diff --git a/src/web/app/base.styl b/src/web/app/app.styl
index 81c039f0a3..94faba73d4 100644
--- a/src/web/app/base.styl
+++ b/src/web/app/app.styl
@@ -5,8 +5,6 @@ json('../../const.json')
$theme-color = themeColor
$theme-color-foreground = themeColorForeground
-@import './reset'
-
/*
::selection
background $theme-color
@@ -14,6 +12,9 @@ $theme-color-foreground = themeColorForeground
*/
*
+ position relative
+ box-sizing border-box
+ background-clip padding-box !important
tap-highlight-color rgba($theme-color, 0.7)
-webkit-tap-highlight-color rgba($theme-color, 0.7)
@@ -29,6 +30,9 @@ html
&, *
cursor progress !important
+body
+ overflow-wrap break-word
+
#error
padding 32px
color #fff
diff --git a/src/web/app/auth/style.styl b/src/web/app/auth/style.styl
index 046a5ff6ee..bd25e1b572 100644
--- a/src/web/app/auth/style.styl
+++ b/src/web/app/auth/style.styl
@@ -1,4 +1,5 @@
-@import "../base"
+@import "../app"
+@import "../reset"
html
background #eee
diff --git a/src/web/app/ch/router.js b/src/web/app/ch/router.js
new file mode 100644
index 0000000000..424158f403
--- /dev/null
+++ b/src/web/app/ch/router.js
@@ -0,0 +1,32 @@
+import * as riot from 'riot';
+const route = require('page');
+let page = null;
+
+export default me => {
+ route('/', index);
+ route('/:channel', channel);
+ route('*', notFound);
+
+ function index() {
+ mount(document.createElement('mk-index'));
+ }
+
+ function channel(ctx) {
+ const el = document.createElement('mk-channel');
+ el.setAttribute('id', ctx.params.channel);
+ mount(el);
+ }
+
+ function notFound() {
+ mount(document.createElement('mk-not-found'));
+ }
+
+ // EXEC
+ route();
+};
+
+function mount(content) {
+ if (page) page.unmount();
+ const body = document.getElementById('app');
+ page = riot.mount(body.appendChild(content))[0];
+}
diff --git a/src/web/app/ch/script.js b/src/web/app/ch/script.js
new file mode 100644
index 0000000000..760d405c52
--- /dev/null
+++ b/src/web/app/ch/script.js
@@ -0,0 +1,18 @@
+/**
+ * Channels
+ */
+
+// Style
+import './style.styl';
+
+require('./tags');
+import init from '../init';
+import route from './router';
+
+/**
+ * init
+ */
+init(me => {
+ // Start routing
+ route(me);
+});
diff --git a/src/web/app/ch/style.styl b/src/web/app/ch/style.styl
new file mode 100644
index 0000000000..21ca648cbe
--- /dev/null
+++ b/src/web/app/ch/style.styl
@@ -0,0 +1,10 @@
+@import "../app"
+
+html
+ padding 8px
+ background #efefef
+
+#wait
+ top auto
+ bottom 15px
+ left 15px
diff --git a/src/web/app/ch/tags/channel.tag b/src/web/app/ch/tags/channel.tag
new file mode 100644
index 0000000000..4ae62e7b39
--- /dev/null
+++ b/src/web/app/ch/tags/channel.tag
@@ -0,0 +1,403 @@
+<mk-channel>
+ <mk-header/>
+ <hr>
+ <main if={ !fetching }>
+ <h1>{ channel.title }</h1>
+
+ <div if={ SIGNIN }>
+ <p if={ channel.is_watching }>このチャンネルをウォッチしています <a onclick={ unwatch }>ウォッチ解除</a></p>
+ <p if={ !channel.is_watching }><a onclick={ watch }>このチャンネルをウォッチする</a></p>
+ </div>
+
+ <div class="share">
+ <mk-twitter-button/>
+ <mk-line-button/>
+ </div>
+
+ <div class="body">
+ <p if={ postsFetching }>読み込み中<mk-ellipsis/></p>
+ <div if={ !postsFetching }>
+ <p if={ posts == null || posts.length == 0 }>まだ投稿がありません</p>
+ <virtual if={ posts != null }>
+ <mk-channel-post each={ post in posts.slice().reverse() } post={ post } form={ parent.refs.form }/>
+ </virtual>
+ </div>
+ </div>
+ <hr>
+ <mk-channel-form if={ SIGNIN } channel={ channel } ref="form"/>
+ <div if={ !SIGNIN }>
+ <p>参加するには<a href={ CONFIG.url }>ログインまたは新規登録</a>してください</p>
+ </div>
+ <hr>
+ <footer>
+ <small><a href={ CONFIG.url }>Misskey</a> ver { version } (葵 aoi)</small>
+ </footer>
+ </main>
+ <style>
+ :scope
+ display block
+
+ > main
+ > h1
+ font-size 1.5em
+ color #f00
+
+ > .share
+ > *
+ margin-right 4px
+
+ > .body
+ margin 8px 0 0 0
+
+ > mk-channel-form
+ max-width 500px
+
+ </style>
+ <script>
+ import Progress from '../../common/scripts/loading';
+ import ChannelStream from '../../common/scripts/channel-stream';
+
+ this.mixin('i');
+ this.mixin('api');
+
+ this.id = this.opts.id;
+ this.fetching = true;
+ this.postsFetching = true;
+ this.channel = null;
+ this.posts = null;
+ this.connection = new ChannelStream(this.id);
+ this.version = VERSION;
+ this.unreadCount = 0;
+
+ this.on('mount', () => {
+ document.documentElement.style.background = '#efefef';
+
+ Progress.start();
+
+ let fetched = false;
+
+ // チャンネル概要読み込み
+ this.api('channels/show', {
+ channel_id: this.id
+ }).then(channel => {
+ if (fetched) {
+ Progress.done();
+ } else {
+ Progress.set(0.5);
+ fetched = true;
+ }
+
+ this.update({
+ fetching: false,
+ channel: channel
+ });
+
+ document.title = channel.title + ' | Misskey'
+ });
+
+ // 投稿読み込み
+ this.api('channels/posts', {
+ channel_id: this.id
+ }).then(posts => {
+ if (fetched) {
+ Progress.done();
+ } else {
+ Progress.set(0.5);
+ fetched = true;
+ }
+
+ this.update({
+ postsFetching: false,
+ posts: posts
+ });
+ });
+
+ this.connection.on('post', this.onPost);
+ document.addEventListener('visibilitychange', this.onVisibilitychange, false);
+ });
+
+ this.on('unmount', () => {
+ this.connection.off('post', this.onPost);
+ this.connection.close();
+ document.removeEventListener('visibilitychange', this.onVisibilitychange);
+ });
+
+ this.onPost = post => {
+ this.posts.unshift(post);
+ this.update();
+
+ if (document.hidden && this.SIGNIN && post.user_id !== this.I.id) {
+ this.unreadCount++;
+ document.title = `(${this.unreadCount}) ${this.channel.title} | Misskey`;
+ }
+ };
+
+ this.onVisibilitychange = () => {
+ if (!document.hidden) {
+ this.unreadCount = 0;
+ document.title = this.channel.title + ' | Misskey'
+ }
+ };
+
+ this.watch = () => {
+ this.api('channels/watch', {
+ channel_id: this.id
+ }).then(() => {
+ this.channel.is_watching = true;
+ this.update();
+ }, e => {
+ alert('error');
+ });
+ };
+
+ this.unwatch = () => {
+ this.api('channels/unwatch', {
+ channel_id: this.id
+ }).then(() => {
+ this.channel.is_watching = false;
+ this.update();
+ }, e => {
+ alert('error');
+ });
+ };
+ </script>
+</mk-channel>
+
+<mk-channel-post>
+ <header>
+ <a class="index" onclick={ reply }>{ post.index }:</a>
+ <a class="name" href={ CONFIG.url + '/' + post.user.username }><b>{ post.user.name }</b></a>
+ <mk-time time={ post.created_at }/>
+ <mk-time time={ post.created_at } mode="detail"/>
+ <span>ID:<i>{ post.user.username }</i></span>
+ </header>
+ <div>
+ <a if={ post.reply }>&gt;&gt;{ post.reply.index }</a>
+ { post.text }
+ <div class="media" if={ post.media }>
+ <virtual each={ file in post.media }>
+ <a href={ file.url } target="_blank">
+ <img src={ file.url + '?thumbnail&size=512' } alt={ file.name } title={ file.name }/>
+ </a>
+ </virtual>
+ </div>
+ </div>
+ <style>
+ :scope
+ display block
+ margin 0
+ padding 0
+
+ > header
+ position -webkit-sticky
+ position sticky
+ z-index 1
+ top 0
+ background rgba(239, 239, 239, 0.9)
+
+ > .index
+ margin-right 0.25em
+ color #000
+
+ > .name
+ margin-right 0.5em
+ color #008000
+
+ > mk-time
+ margin-right 0.5em
+
+ &:first-of-type
+ display none
+
+ @media (max-width 600px)
+ > mk-time
+ &:first-of-type
+ display initial
+
+ &:last-of-type
+ display none
+
+ > div
+ padding 0 0 1em 2em
+
+ > .media
+ > a
+ display inline-block
+
+ > img
+ max-width 100%
+ vertical-align bottom
+
+ </style>
+ <script>
+ this.post = this.opts.post;
+ this.form = this.opts.form;
+
+ this.reply = () => {
+ this.form.update({
+ reply: this.post
+ });
+ };
+ </script>
+</mk-channel-post>
+
+<mk-channel-form>
+ <p if={ reply }><b>&gt;&gt;{ reply.index }</b> ({ reply.user.name }): <a onclick={ clearReply }>[x]</a></p>
+ <textarea ref="text" disabled={ wait } oninput={ update } onkeydown={ onkeydown } onpaste={ onpaste } placeholder="%i18n:ch.tags.mk-channel-form.textarea%"></textarea>
+ <div class="actions">
+ <button onclick={ selectFile }><i class="fa fa-upload"></i>%i18n:ch.tags.mk-channel-form.upload%</button>
+ <button onclick={ drive }><i class="fa fa-cloud"></i>%i18n:ch.tags.mk-channel-form.drive%</button>
+ <button class={ wait: wait } ref="submit" disabled={ wait || (refs.text.value.length == 0) } onclick={ post }>
+ <i class="fa fa-paper-plane" if={ !wait }></i>{ wait ? '%i18n:ch.tags.mk-channel-form.posting%' : '%i18n:ch.tags.mk-channel-form.post%' }<mk-ellipsis if={ wait }/>
+ </button>
+ </div>
+ <mk-uploader ref="uploader"/>
+ <ol if={ files }>
+ <li each={ files }>{ name }</li>
+ </ol>
+ <input ref="file" type="file" accept="image/*" multiple="multiple" onchange={ changeFile }/>
+ <style>
+ :scope
+ display block
+
+ > textarea
+ width 100%
+ max-width 100%
+ min-width 100%
+ min-height 5em
+
+ > .actions
+ display flex
+
+ > button
+ > i
+ margin-right 0.25em
+
+ &:last-child
+ margin-left auto
+
+ &.wait
+ cursor wait
+
+ > input[type='file']
+ display none
+
+ </style>
+ <script>
+ import CONFIG from '../../common/scripts/config';
+
+ this.mixin('api');
+
+ this.channel = this.opts.channel;
+ this.files = null;
+
+ this.on('mount', () => {
+ this.refs.uploader.on('uploaded', file => {
+ this.update({
+ files: [file]
+ });
+ });
+ });
+
+ this.upload = file => {
+ this.refs.uploader.upload(file);
+ };
+
+ this.clearReply = () => {
+ this.update({
+ reply: null
+ });
+ };
+
+ this.clear = () => {
+ this.clearReply();
+ this.update({
+ files: null
+ });
+ this.refs.text.value = '';
+ };
+
+ this.post = () => {
+ this.update({
+ wait: true
+ });
+
+ const files = this.files && this.files.length > 0
+ ? this.files.map(f => f.id)
+ : undefined;
+
+ this.api('posts/create', {
+ text: this.refs.text.value == '' ? undefined : this.refs.text.value,
+ media_ids: files,
+ reply_id: this.reply ? this.reply.id : undefined,
+ channel_id: this.channel.id
+ }).then(data => {
+ this.clear();
+ }).catch(err => {
+ alert('失敗した');
+ }).then(() => {
+ this.update({
+ wait: false
+ });
+ });
+ };
+
+ this.changeFile = () => {
+ this.refs.file.files.forEach(this.upload);
+ };
+
+ this.selectFile = () => {
+ this.refs.file.click();
+ };
+
+ this.drive = () => {
+ window['cb'] = files => {
+ this.update({
+ files: files
+ });
+ };
+
+ window.open(CONFIG.url + '/selectdrive?multiple=true',
+ 'drive_window',
+ 'height=500,width=800');
+ };
+
+ this.onkeydown = e => {
+ if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.metaKey)) this.post();
+ };
+
+ this.onpaste = e => {
+ e.clipboardData.items.forEach(item => {
+ if (item.kind == 'file') {
+ this.upload(item.getAsFile());
+ }
+ });
+ };
+ </script>
+</mk-channel-form>
+
+<mk-twitter-button>
+ <a href="https://twitter.com/share?ref_src=twsrc%5Etfw" class="twitter-share-button" data-show-count="false">Tweet</a>
+ <script>
+ this.on('mount', () => {
+ const head = document.getElementsByTagName('head')[0];
+ const script = document.createElement('script');
+ script.setAttribute('src', 'https://platform.twitter.com/widgets.js');
+ script.setAttribute('async', 'async');
+ head.appendChild(script);
+ });
+ </script>
+</mk-twitter-button>
+
+<mk-line-button>
+ <div class="line-it-button" data-lang="ja" data-type="share-a" data-url={ CONFIG.chUrl } style="display: none;"></div>
+ <script>
+ this.on('mount', () => {
+ const head = document.getElementsByTagName('head')[0];
+ const script = document.createElement('script');
+ script.setAttribute('src', 'https://d.line-scdn.net/r/web/social-plugin/js/thirdparty/loader.min.js');
+ script.setAttribute('async', 'async');
+ head.appendChild(script);
+ });
+ </script>
+</mk-line-button>
diff --git a/src/web/app/ch/tags/header.tag b/src/web/app/ch/tags/header.tag
new file mode 100644
index 0000000000..5cdcbd09cc
--- /dev/null
+++ b/src/web/app/ch/tags/header.tag
@@ -0,0 +1,20 @@
+<mk-header>
+ <div>
+ <a href={ CONFIG.chUrl }>Index</a> | <a href={ CONFIG.url }>Misskey</a>
+ </div>
+ <div>
+ <a if={ !SIGNIN } href={ CONFIG.url }>ログイン(新規登録)</a>
+ <a if={ SIGNIN } href={ CONFIG.url + '/' + I.username }>{ I.username }</a>
+ </div>
+ <style>
+ :scope
+ display flex
+
+ > div:last-child
+ margin-left auto
+
+ </style>
+ <script>
+ this.mixin('i');
+ </script>
+</mk-header>
diff --git a/src/web/app/ch/tags/index.js b/src/web/app/ch/tags/index.js
new file mode 100644
index 0000000000..12ffdaeb84
--- /dev/null
+++ b/src/web/app/ch/tags/index.js
@@ -0,0 +1,3 @@
+require('./index.tag');
+require('./channel.tag');
+require('./header.tag');
diff --git a/src/web/app/ch/tags/index.tag b/src/web/app/ch/tags/index.tag
new file mode 100644
index 0000000000..50ccc0d91c
--- /dev/null
+++ b/src/web/app/ch/tags/index.tag
@@ -0,0 +1,35 @@
+<mk-index>
+ <mk-header/>
+ <hr>
+ <button onclick={ n }>%i18n:ch.tags.mk-index.new%</button>
+ <hr>
+ <ul if={ channels }>
+ <li each={ channels }><a href={ '/' + this.id }>{ this.title }</a></li>
+ </ul>
+ <style>
+ :scope
+ display block
+
+ </style>
+ <script>
+ this.mixin('api');
+
+ this.on('mount', () => {
+ this.api('channels').then(channels => {
+ this.update({
+ channels: channels
+ });
+ });
+ });
+
+ this.n = () => {
+ const title = window.prompt('%i18n:ch.tags.mk-index.channel-title%');
+
+ this.api('channels/create', {
+ title: title
+ }).then(channel => {
+ location.href = '/' + channel.id;
+ });
+ };
+ </script>
+</mk-index>
diff --git a/src/web/app/common/scripts/channel-stream.js b/src/web/app/common/scripts/channel-stream.js
new file mode 100644
index 0000000000..17944dbe45
--- /dev/null
+++ b/src/web/app/common/scripts/channel-stream.js
@@ -0,0 +1,16 @@
+'use strict';
+
+import Stream from './stream';
+
+/**
+ * Channel stream connection
+ */
+class Connection extends Stream {
+ constructor(channelId) {
+ super('channel', {
+ channel: channelId
+ });
+ }
+}
+
+export default Connection;
diff --git a/src/web/app/common/scripts/config.js b/src/web/app/common/scripts/config.js
index 75a7abba29..c5015622f0 100644
--- a/src/web/app/common/scripts/config.js
+++ b/src/web/app/common/scripts/config.js
@@ -6,6 +6,7 @@ const host = isRoot ? Url.host : Url.host.substring(Url.host.indexOf('.') + 1, U
const scheme = Url.protocol;
const url = `${scheme}//${host}`;
const apiUrl = `${scheme}//api.${host}`;
+const chUrl = `${scheme}//ch.${host}`;
const devUrl = `${scheme}//dev.${host}`;
const aboutUrl = `${scheme}//about.${host}`;
const statsUrl = `${scheme}//stats.${host}`;
@@ -16,6 +17,7 @@ export default {
scheme,
url,
apiUrl,
+ chUrl,
devUrl,
aboutUrl,
statsUrl,
diff --git a/src/web/app/desktop/router.js b/src/web/app/desktop/router.js
index afa8a2dce3..977e3fa9a6 100644
--- a/src/web/app/desktop/router.js
+++ b/src/web/app/desktop/router.js
@@ -7,14 +7,15 @@ const route = require('page');
let page = null;
export default me => {
- route('/', index);
- route('/i>mentions', mentions);
- route('/post::post', post);
- route('/search::query', search);
- route('/:user', user.bind(null, 'home'));
- route('/:user/graphs', user.bind(null, 'graphs'));
- route('/:user/:post', post);
- route('*', notFound);
+ route('/', index);
+ route('/selectdrive', selectDrive);
+ route('/i>mentions', mentions);
+ route('/post::post', post);
+ route('/search::query', search);
+ route('/:user', user.bind(null, 'home'));
+ route('/:user/graphs', user.bind(null, 'graphs'));
+ route('/:user/:post', post);
+ route('*', notFound);
function index() {
me ? home() : entrance();
@@ -54,6 +55,10 @@ export default me => {
mount(el);
}
+ function selectDrive() {
+ mount(document.createElement('mk-selectdrive-page'));
+ }
+
function notFound() {
mount(document.createElement('mk-not-found'));
}
@@ -67,6 +72,7 @@ export default me => {
};
function mount(content) {
+ document.documentElement.style.background = '#313a42';
document.documentElement.removeAttribute('data-page');
if (page) page.unmount();
const body = document.getElementById('app');
diff --git a/src/web/app/desktop/style.styl b/src/web/app/desktop/style.styl
index 88adb68b2b..4597dffdb3 100644
--- a/src/web/app/desktop/style.styl
+++ b/src/web/app/desktop/style.styl
@@ -1,4 +1,5 @@
-@import "../base"
+@import "../app"
+@import "../reset"
@import "../../../../node_modules/cropperjs/dist/cropper.css"
*::input-placeholder
diff --git a/src/web/app/desktop/tags/home-widgets/rss-reader.tag b/src/web/app/desktop/tags/home-widgets/rss-reader.tag
index 550d7e76de..e9b740762e 100644
--- a/src/web/app/desktop/tags/home-widgets/rss-reader.tag
+++ b/src/web/app/desktop/tags/home-widgets/rss-reader.tag
@@ -4,7 +4,7 @@
<div class="feed" if={ !initializing }>
<virtual each={ item in items }><a href={ item.link } target="_blank">{ item.title }</a></virtual>
</div>
- <p class="initializing" if={ initializing }><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます<mk-ellipsis/></p>
+ <p class="initializing" if={ initializing }><i class="fa fa-spinner fa-pulse fa-fw"></i>%i18n:common.loading%<mk-ellipsis/></p>
<style>
:scope
display block
diff --git a/src/web/app/desktop/tags/index.js b/src/web/app/desktop/tags/index.js
index 4e286013a1..37fdfe37e4 100644
--- a/src/web/app/desktop/tags/index.js
+++ b/src/web/app/desktop/tags/index.js
@@ -61,6 +61,7 @@ require('./pages/user.tag');
require('./pages/post.tag');
require('./pages/search.tag');
require('./pages/not-found.tag');
+require('./pages/selectdrive.tag');
require('./autocomplete-suggestion.tag');
require('./progress-dialog.tag');
require('./user-preview.tag');
diff --git a/src/web/app/desktop/tags/notifications.tag b/src/web/app/desktop/tags/notifications.tag
index 1046358ce9..a4f66105a8 100644
--- a/src/web/app/desktop/tags/notifications.tag
+++ b/src/web/app/desktop/tags/notifications.tag
@@ -252,6 +252,12 @@
});
this.onNotification = notification => {
+ // TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
+ this.stream.send({
+ type: 'read_notification',
+ id: notification.id
+ });
+
this.notifications.unshift(notification);
this.update();
};
diff --git a/src/web/app/desktop/tags/pages/selectdrive.tag b/src/web/app/desktop/tags/pages/selectdrive.tag
new file mode 100644
index 0000000000..b196357d85
--- /dev/null
+++ b/src/web/app/desktop/tags/pages/selectdrive.tag
@@ -0,0 +1,159 @@
+<mk-selectdrive-page>
+ <mk-drive-browser ref="browser" multiple={ multiple }/>
+ <div>
+ <button class="upload" title="PCからドライブにファイルをアップロード" onclick={ upload }><i class="fa fa-upload"></i></button>
+ <button class="cancel" onclick={ close }>キャンセル</button>
+ <button class="ok" onclick={ ok }>決定</button>
+ </div>
+
+ <style>
+ :scope
+ display block
+ height 100%
+ background #fff
+
+ > mk-drive-browser
+ height calc(100% - 72px)
+
+ > div
+ position fixed
+ bottom 0
+ left 0
+ width 100%
+ height 72px
+ background lighten($theme-color, 95%)
+
+ .upload
+ display inline-block
+ position absolute
+ top 8px
+ left 16px
+ cursor pointer
+ padding 0
+ margin 8px 4px 0 0
+ width 40px
+ height 40px
+ font-size 1em
+ color rgba($theme-color, 0.5)
+ background transparent
+ outline none
+ border solid 1px transparent
+ border-radius 4px
+
+ &:hover
+ background transparent
+ border-color rgba($theme-color, 0.3)
+
+ &:active
+ color rgba($theme-color, 0.6)
+ background transparent
+ border-color rgba($theme-color, 0.5)
+ box-shadow 0 2px 4px rgba(darken($theme-color, 50%), 0.15) inset
+
+ &:focus
+ &:after
+ content ""
+ pointer-events none
+ position absolute
+ top -5px
+ right -5px
+ bottom -5px
+ left -5px
+ border 2px solid rgba($theme-color, 0.3)
+ border-radius 8px
+
+ .ok
+ .cancel
+ display block
+ position absolute
+ bottom 16px
+ cursor pointer
+ padding 0
+ margin 0
+ width 120px
+ height 40px
+ font-size 1em
+ outline none
+ border-radius 4px
+
+ &:focus
+ &:after
+ content ""
+ pointer-events none
+ position absolute
+ top -5px
+ right -5px
+ bottom -5px
+ left -5px
+ border 2px solid rgba($theme-color, 0.3)
+ border-radius 8px
+
+ &:disabled
+ opacity 0.7
+ cursor default
+
+ .ok
+ right 16px
+ color $theme-color-foreground
+ background linear-gradient(to bottom, lighten($theme-color, 25%) 0%, lighten($theme-color, 10%) 100%)
+ border solid 1px lighten($theme-color, 15%)
+
+ &:not(:disabled)
+ font-weight bold
+
+ &:hover:not(:disabled)
+ background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%)
+ border-color $theme-color
+
+ &:active:not(:disabled)
+ background $theme-color
+ border-color $theme-color
+
+ .cancel
+ right 148px
+ color #888
+ background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
+ border solid 1px #e2e2e2
+
+ &:hover
+ background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
+ border-color #dcdcdc
+
+ &:active
+ background #ececec
+ border-color #dcdcdc
+
+ </style>
+ <script>
+ const q = (new URL(location)).searchParams;
+ this.multiple = q.get('multiple') == 'true' ? true : false;
+
+ this.on('mount', () => {
+ document.documentElement.style.background = '#fff';
+
+ this.refs.browser.on('selected', file => {
+ this.files = [file];
+ this.ok();
+ });
+
+ this.refs.browser.on('change-selection', files => {
+ this.update({
+ files: files
+ });
+ });
+ });
+
+ this.upload = () => {
+ this.refs.browser.selectLocalFile();
+ };
+
+ this.close = () => {
+ window.close();
+ };
+
+ this.ok = () => {
+ window.opener.cb(this.multiple ? this.files : this.files[0]);
+ window.close();
+ };
+ </script>
+</mk-selectdrive-page>
diff --git a/src/web/app/desktop/tags/pages/user.tag b/src/web/app/desktop/tags/pages/user.tag
index 864fe22735..811ca5c0fd 100644
--- a/src/web/app/desktop/tags/pages/user.tag
+++ b/src/web/app/desktop/tags/pages/user.tag
@@ -16,7 +16,7 @@
this.refs.ui.refs.user.on('user-fetched', user => {
Progress.set(0.5);
- document.title = user.name + ' | Misskey'
+ document.title = user.name + ' | Misskey';
});
this.refs.ui.refs.user.on('loaded', () => {
diff --git a/src/web/app/desktop/tags/post-detail.tag b/src/web/app/desktop/tags/post-detail.tag
index 58343482d0..ce7f81e32c 100644
--- a/src/web/app/desktop/tags/post-detail.tag
+++ b/src/web/app/desktop/tags/post-detail.tag
@@ -1,6 +1,6 @@
<mk-post-detail title={ title }>
<div class="main">
- <button class="read-more" if={ p.reply_to && p.reply_to.reply_to_id && context == null } title="会話をもっと読み込む" onclick={ loadContext } disabled={ contextFetching }>
+ <button class="read-more" if={ p.reply && p.reply.reply_id && context == null } title="会話をもっと読み込む" onclick={ loadContext } disabled={ contextFetching }>
<i class="fa fa-ellipsis-v" if={ !contextFetching }></i>
<i class="fa fa-spinner fa-pulse" if={ contextFetching }></i>
</button>
@@ -9,8 +9,8 @@
<mk-post-detail-sub post={ post }/>
</virtual>
</div>
- <div class="reply-to" if={ p.reply_to }>
- <mk-post-detail-sub post={ p.reply_to }/>
+ <div class="reply-to" if={ p.reply }>
+ <mk-post-detail-sub post={ p.reply }/>
</div>
<div class="repost" if={ isRepost }>
<p>
@@ -329,7 +329,7 @@
// Fetch context
this.api('posts/context', {
- post_id: this.p.reply_to_id
+ post_id: this.p.reply_id
}).then(context => {
this.update({
contextFetching: false,
diff --git a/src/web/app/desktop/tags/post-form.tag b/src/web/app/desktop/tags/post-form.tag
index 6a363d67cd..5041078bee 100644
--- a/src/web/app/desktop/tags/post-form.tag
+++ b/src/web/app/desktop/tags/post-form.tag
@@ -475,7 +475,7 @@
this.api('posts/create', {
text: this.refs.text.value == '' ? undefined : this.refs.text.value,
media_ids: files,
- reply_to_id: this.inReplyToPost ? this.inReplyToPost.id : undefined,
+ reply_id: this.inReplyToPost ? this.inReplyToPost.id : undefined,
repost_id: this.repost ? this.repost.id : undefined,
poll: this.poll ? this.refs.poll.get() : undefined
}).then(data => {
diff --git a/src/web/app/desktop/tags/sub-post-content.tag b/src/web/app/desktop/tags/sub-post-content.tag
index 02cb5251b2..c75ae2911c 100644
--- a/src/web/app/desktop/tags/sub-post-content.tag
+++ b/src/web/app/desktop/tags/sub-post-content.tag
@@ -1,6 +1,6 @@
<mk-sub-post-content>
<div class="body">
- <a class="reply" if={ post.reply_to_id }>
+ <a class="reply" if={ post.reply_id }>
<i class="fa fa-reply"></i>
</a>
<span ref="text"></span>
diff --git a/src/web/app/desktop/tags/timeline.tag b/src/web/app/desktop/tags/timeline.tag
index 2d6b439e38..44f3d5d8ec 100644
--- a/src/web/app/desktop/tags/timeline.tag
+++ b/src/web/app/desktop/tags/timeline.tag
@@ -82,8 +82,8 @@
</mk-timeline>
<mk-timeline-post tabindex="-1" title={ title } onkeydown={ onKeyDown } dblclick={ onDblClick }>
- <div class="reply-to" if={ p.reply_to }>
- <mk-timeline-post-sub post={ p.reply_to }/>
+ <div class="reply-to" if={ p.reply }>
+ <mk-timeline-post-sub post={ p.reply }/>
</div>
<div class="repost" if={ isRepost }>
<p>
@@ -112,7 +112,8 @@
</header>
<div class="body">
<div class="text" ref="text">
- <a class="reply" if={ p.reply_to }>
+ <p class="channel" if={ p.channel != null }><a href={ CONFIG.chUrl + '/' + p.channel.id } target="_blank">{ p.channel.title }</a>:</p>
+ <a class="reply" if={ p.reply }>
<i class="fa fa-reply"></i>
</a>
<p class="dummy"></p>
@@ -333,6 +334,9 @@
font-weight 400
font-style normal
+ > .channel
+ margin 0
+
> .reply
margin-right 8px
color #717171
diff --git a/src/web/app/desktop/tags/ui.tag b/src/web/app/desktop/tags/ui.tag
index e0d7393b08..3123c34f4f 100644
--- a/src/web/app/desktop/tags/ui.tag
+++ b/src/web/app/desktop/tags/ui.tag
@@ -319,18 +319,26 @@
</mk-ui-header-notifications>
<mk-ui-header-nav>
- <ul if={ SIGNIN }>
- <li class="home { active: page == 'home' }">
- <a href={ CONFIG.url }>
- <i class="fa fa-home"></i>
- <p>%i18n:desktop.tags.mk-ui-header-nav.home%</p>
- </a>
- </li>
- <li class="messaging">
- <a onclick={ messaging }>
- <i class="fa fa-comments"></i>
- <p>%i18n:desktop.tags.mk-ui-header-nav.messaging%</p>
- <i class="fa fa-circle" if={ hasUnreadMessagingMessages }></i>
+ <ul>
+ <virtual if={ SIGNIN }>
+ <li class="home { active: page == 'home' }">
+ <a href={ CONFIG.url }>
+ <i class="fa fa-home"></i>
+ <p>%i18n:desktop.tags.mk-ui-header-nav.home%</p>
+ </a>
+ </li>
+ <li class="messaging">
+ <a onclick={ messaging }>
+ <i class="fa fa-comments"></i>
+ <p>%i18n:desktop.tags.mk-ui-header-nav.messaging%</p>
+ <i class="fa fa-circle" if={ hasUnreadMessagingMessages }></i>
+ </a>
+ </li>
+ </virtual>
+ <li class="ch">
+ <a href={ CONFIG.chUrl } target="_blank">
+ <i class="fa fa-television"></i>
+ <p>%i18n:desktop.tags.mk-ui-header-nav.ch%</p>
</a>
</li>
<li class="info">
diff --git a/src/web/app/dev/style.styl b/src/web/app/dev/style.styl
index 4fd537709d..cdbcb0e261 100644
--- a/src/web/app/dev/style.styl
+++ b/src/web/app/dev/style.styl
@@ -1,4 +1,5 @@
-@import "../base"
+@import "../app"
+@import "../reset"
html
background-color #fff
diff --git a/src/web/app/mobile/router.js b/src/web/app/mobile/router.js
index d59b2ec3a1..01eb3c8145 100644
--- a/src/web/app/mobile/router.js
+++ b/src/web/app/mobile/router.js
@@ -8,6 +8,7 @@ let page = null;
export default me => {
route('/', index);
+ route('/selectdrive', selectDrive);
route('/i/notifications', notifications);
route('/i/messaging', messaging);
route('/i/messaging/:username', messaging);
@@ -122,6 +123,10 @@ export default me => {
mount(el);
}
+ function selectDrive() {
+ mount(document.createElement('mk-selectdrive-page'));
+ }
+
function notFound() {
mount(document.createElement('mk-not-found'));
}
diff --git a/src/web/app/mobile/style.styl b/src/web/app/mobile/style.styl
index bd6965e402..63e4f2349f 100644
--- a/src/web/app/mobile/style.styl
+++ b/src/web/app/mobile/style.styl
@@ -1,4 +1,5 @@
-@import "../base"
+@import "../app"
+@import "../reset"
#wait
top auto
diff --git a/src/web/app/mobile/tags/drive.tag b/src/web/app/mobile/tags/drive.tag
index 9f3e647735..6929c50ab1 100644
--- a/src/web/app/mobile/tags/drive.tag
+++ b/src/web/app/mobile/tags/drive.tag
@@ -1,5 +1,5 @@
<mk-drive>
- <nav>
+ <nav ref="nav">
<p onclick={ goRoot }><i class="fa fa-cloud"></i>%i18n:mobile.tags.mk-drive.drive%</p>
<virtual each={ folder in hierarchyFolders }>
<span><i class="fa fa-angle-right"></i></span>
@@ -56,10 +56,6 @@
display block
background #fff
- &[data-is-naked]
- > nav
- top 48px
-
> nav
display block
position sticky
@@ -205,6 +201,10 @@
} else {
this.fetch();
}
+
+ if (this.opts.isNaked) {
+ this.refs.nav.style.top = `${this.opts.top}px`;
+ }
});
this.on('unmount', () => {
@@ -483,7 +483,7 @@
if (fn == null || fn == '') return;
switch (fn) {
case '1':
- this.refs.file.click();
+ this.selectLocalFile();
break;
case '2':
this.urlUpload();
@@ -503,6 +503,10 @@
}
};
+ this.selectLocalFile = () => {
+ this.refs.file.click();
+ };
+
this.createFolder = () => {
const name = window.prompt('フォルダー名');
if (name == null || name == '') return;
diff --git a/src/web/app/mobile/tags/index.js b/src/web/app/mobile/tags/index.js
index c5aafd20ba..19952c20cd 100644
--- a/src/web/app/mobile/tags/index.js
+++ b/src/web/app/mobile/tags/index.js
@@ -1,6 +1,4 @@
require('./ui.tag');
-require('./ui-header.tag');
-require('./ui-nav.tag');
require('./page/entrance.tag');
require('./page/entrance/signin.tag');
require('./page/entrance/signup.tag');
@@ -21,6 +19,7 @@ require('./page/settings/authorized-apps.tag');
require('./page/settings/twitter.tag');
require('./page/messaging.tag');
require('./page/messaging-room.tag');
+require('./page/selectdrive.tag');
require('./home.tag');
require('./home-timeline.tag');
require('./timeline.tag');
diff --git a/src/web/app/mobile/tags/notifications.tag b/src/web/app/mobile/tags/notifications.tag
index 7370aa84d3..2e95990314 100644
--- a/src/web/app/mobile/tags/notifications.tag
+++ b/src/web/app/mobile/tags/notifications.tag
@@ -123,6 +123,12 @@
});
this.onNotification = notification => {
+ // TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
+ this.stream.send({
+ type: 'read_notification',
+ id: notification.id
+ });
+
this.notifications.unshift(notification);
this.update();
};
diff --git a/src/web/app/mobile/tags/page/drive.tag b/src/web/app/mobile/tags/page/drive.tag
index 1169e3b9eb..218960c702 100644
--- a/src/web/app/mobile/tags/page/drive.tag
+++ b/src/web/app/mobile/tags/page/drive.tag
@@ -1,6 +1,6 @@
<mk-drive-page>
<mk-ui ref="ui">
- <mk-drive ref="browser" folder={ parent.opts.folder } file={ parent.opts.file } data-is-naked="true"/>
+ <mk-drive ref="browser" folder={ parent.opts.folder } file={ parent.opts.file } is-naked={ true } top={ 48 }/>
</mk-ui>
<style>
:scope
diff --git a/src/web/app/mobile/tags/page/notifications.tag b/src/web/app/mobile/tags/page/notifications.tag
index 06a5be039f..743de04393 100644
--- a/src/web/app/mobile/tags/page/notifications.tag
+++ b/src/web/app/mobile/tags/page/notifications.tag
@@ -10,16 +10,30 @@
import ui from '../../scripts/ui-event';
import Progress from '../../../common/scripts/loading';
+ this.mixin('api');
+
this.on('mount', () => {
document.title = 'Misskey | %i18n:mobile.tags.mk-notifications-page.notifications%';
ui.trigger('title', '<i class="fa fa-bell-o"></i>%i18n:mobile.tags.mk-notifications-page.notifications%');
document.documentElement.style.background = '#313a42';
+ ui.trigger('func', () => {
+ this.readAll();
+ }, 'check');
+
Progress.start();
this.refs.ui.refs.notifications.on('fetched', () => {
Progress.done();
});
});
+
+ this.readAll = () => {
+ const ok = window.confirm('%i18n:mobile.tags.mk-notifications-page.read-all%');
+
+ if (!ok) return;
+
+ this.api('notifications/mark_as_read_all');
+ };
</script>
</mk-notifications-page>
diff --git a/src/web/app/mobile/tags/page/selectdrive.tag b/src/web/app/mobile/tags/page/selectdrive.tag
new file mode 100644
index 0000000000..79ea3548f8
--- /dev/null
+++ b/src/web/app/mobile/tags/page/selectdrive.tag
@@ -0,0 +1,87 @@
+<mk-selectdrive-page>
+ <header>
+ <h1>%i18n:mobile.tags.mk-selectdrive-page.select-file%<span class="count" if={ files.length > 0 }>({ files.length })</span></h1>
+ <button class="upload" onclick={ upload }><i class="fa fa-upload"></i></button>
+ <button if={ multiple } class="ok" onclick={ ok }><i class="fa fa-check"></i></button>
+ </header>
+ <mk-drive ref="browser" select-file={ true } multiple={ multiple } is-naked={ true } top={ 42 }/>
+
+ <style>
+ :scope
+ display block
+ width 100%
+ height 100%
+ background #fff
+
+ > header
+ position fixed
+ top 0
+ left 0
+ width 100%
+ z-index 1000
+ background #fff
+ box-shadow 0 1px rgba(0, 0, 0, 0.1)
+
+ > h1
+ margin 0
+ padding 0
+ text-align center
+ line-height 42px
+ font-size 1em
+ font-weight normal
+
+ > .count
+ margin-left 4px
+ opacity 0.5
+
+ > .upload
+ position absolute
+ top 0
+ left 0
+ line-height 42px
+ width 42px
+
+ > .ok
+ position absolute
+ top 0
+ right 0
+ line-height 42px
+ width 42px
+
+ > mk-drive
+ top 42px
+
+ </style>
+ <script>
+ const q = (new URL(location)).searchParams;
+ this.multiple = q.get('multiple') == 'true' ? true : false;
+
+ this.on('mount', () => {
+ document.documentElement.style.background = '#fff';
+
+ this.refs.browser.on('selected', file => {
+ this.files = [file];
+ this.ok();
+ });
+
+ this.refs.browser.on('change-selection', files => {
+ this.update({
+ files: files
+ });
+ });
+ });
+
+ this.upload = () => {
+ this.refs.browser.selectLocalFile();
+ };
+
+ this.close = () => {
+ window.close();
+ };
+
+ this.ok = () => {
+ window.opener.cb(this.multiple ? this.files : this.files[0]);
+ window.close();
+ };
+ </script>
+</mk-selectdrive-page>
diff --git a/src/web/app/mobile/tags/post-detail.tag b/src/web/app/mobile/tags/post-detail.tag
index ed275749ec..8a32101036 100644
--- a/src/web/app/mobile/tags/post-detail.tag
+++ b/src/web/app/mobile/tags/post-detail.tag
@@ -1,5 +1,5 @@
<mk-post-detail>
- <button class="read-more" if={ p.reply_to && p.reply_to.reply_to_id && context == null } onclick={ loadContext } disabled={ loadingContext }>
+ <button class="read-more" if={ p.reply && p.reply.reply_id && context == null } onclick={ loadContext } disabled={ loadingContext }>
<i class="fa fa-ellipsis-v" if={ !contextFetching }></i>
<i class="fa fa-spinner fa-pulse" if={ contextFetching }></i>
</button>
@@ -8,8 +8,8 @@
<mk-post-detail-sub post={ post }/>
</virtual>
</div>
- <div class="reply-to" if={ p.reply_to }>
- <mk-post-detail-sub post={ p.reply_to }/>
+ <div class="reply-to" if={ p.reply }>
+ <mk-post-detail-sub post={ p.reply }/>
</div>
<div class="repost" if={ isRepost }>
<p>
@@ -348,7 +348,7 @@
// Fetch context
this.api('posts/context', {
- post_id: this.p.reply_to_id
+ post_id: this.p.reply_id
}).then(context => {
this.update({
contextFetching: false,
diff --git a/src/web/app/mobile/tags/post-form.tag b/src/web/app/mobile/tags/post-form.tag
index cf267de94a..d7d382c9e2 100644
--- a/src/web/app/mobile/tags/post-form.tag
+++ b/src/web/app/mobile/tags/post-form.tag
@@ -267,7 +267,7 @@
this.api('posts/create', {
text: this.refs.text.value == '' ? undefined : this.refs.text.value,
media_ids: files,
- reply_to_id: opts.reply ? opts.reply.id : undefined,
+ reply_id: opts.reply ? opts.reply.id : undefined,
poll: this.poll ? this.refs.poll.get() : undefined
}).then(data => {
this.trigger('post');
diff --git a/src/web/app/mobile/tags/sub-post-content.tag b/src/web/app/mobile/tags/sub-post-content.tag
index 97e0ecec03..e32e245185 100644
--- a/src/web/app/mobile/tags/sub-post-content.tag
+++ b/src/web/app/mobile/tags/sub-post-content.tag
@@ -1,5 +1,5 @@
<mk-sub-post-content>
- <div class="body"><a class="reply" if={ post.reply_to_id }><i class="fa fa-reply"></i></a><span ref="text"></span><a class="quote" if={ post.repost_id } href={ '/post:' + post.repost_id }>RP: ...</a></div>
+ <div class="body"><a class="reply" if={ post.reply_id }><i class="fa fa-reply"></i></a><span ref="text"></span><a class="quote" if={ post.repost_id } href={ '/post:' + post.repost_id }>RP: ...</a></div>
<details if={ post.media }>
<summary>({ post.media.length }個のメディア)</summary>
<mk-images-viewer images={ post.media }/>
diff --git a/src/web/app/mobile/tags/timeline.tag b/src/web/app/mobile/tags/timeline.tag
index c7f5bfd681..f9ec2cca60 100644
--- a/src/web/app/mobile/tags/timeline.tag
+++ b/src/web/app/mobile/tags/timeline.tag
@@ -137,8 +137,8 @@
</mk-timeline>
<mk-timeline-post class={ repost: isRepost }>
- <div class="reply-to" if={ p.reply_to }>
- <mk-timeline-post-sub post={ p.reply_to }/>
+ <div class="reply-to" if={ p.reply }>
+ <mk-timeline-post-sub post={ p.reply }/>
</div>
<div class="repost" if={ isRepost }>
<p>
@@ -164,7 +164,8 @@
</header>
<div class="body">
<div class="text" ref="text">
- <a class="reply" if={ p.reply_to }>
+ <p class="channel" if={ p.channel != null }><a href={ CONFIG.chUrl + '/' + p.channel.id } target="_blank">{ p.channel.title }</a>:</p>
+ <a class="reply" if={ p.reply }>
<i class="fa fa-reply"></i>
</a>
<p class="dummy"></p>
@@ -373,6 +374,9 @@
mk-url-preview
margin-top 8px
+ > .channel
+ margin 0
+
> .reply
margin-right 8px
color #717171
diff --git a/src/web/app/mobile/tags/ui-header.tag b/src/web/app/mobile/tags/ui-header.tag
deleted file mode 100644
index 10b44b2153..0000000000
--- a/src/web/app/mobile/tags/ui-header.tag
+++ /dev/null
@@ -1,156 +0,0 @@
-<mk-ui-header>
- <mk-special-message/>
- <div class="main">
- <div class="backdrop"></div>
- <div class="content">
- <button class="nav" onclick={ parent.toggleDrawer }><i class="fa fa-bars"></i></button>
- <i class="fa fa-circle" if={ hasUnreadMessagingMessages }></i>
- <h1 ref="title">Misskey</h1>
- <button if={ func } onclick={ func }><i class="fa fa-{ funcIcon }"></i></button>
- </div>
- </div>
- <style>
- :scope
- $height = 48px
-
- display block
- position fixed
- top 0
- z-index 1024
- width 100%
- box-shadow 0 1px 0 rgba(#000, 0.075)
-
- > .main
- color rgba(#fff, 0.9)
-
- > .backdrop
- position absolute
- top 0
- z-index 1023
- width 100%
- height $height
- -webkit-backdrop-filter blur(12px)
- backdrop-filter blur(12px)
- background-color rgba(#1b2023, 0.75)
-
- > .content
- z-index 1024
-
- > h1
- display block
- margin 0 auto
- padding 0
- width 100%
- max-width calc(100% - 112px)
- text-align center
- font-size 1.1em
- font-weight normal
- line-height $height
- white-space nowrap
- overflow hidden
- text-overflow ellipsis
-
- > i
- > .icon
- margin-right 8px
-
- > img
- display inline-block
- vertical-align bottom
- width ($height - 16px)
- height ($height - 16px)
- margin 8px
- border-radius 6px
-
- > .nav
- display block
- position absolute
- top 0
- left 0
- width $height
- font-size 1.4em
- line-height $height
- border-right solid 1px rgba(#000, 0.1)
-
- > i
- transition all 0.2s ease
-
- > i
- position absolute
- top 8px
- left 8px
- pointer-events none
- font-size 10px
- color $theme-color
-
- > button:last-child
- display block
- position absolute
- top 0
- right 0
- width $height
- text-align center
- font-size 1.4em
- color inherit
- line-height $height
- border-left solid 1px rgba(#000, 0.1)
-
- </style>
- <script>
- import ui from '../scripts/ui-event';
-
- this.mixin('api');
- this.mixin('stream');
-
- this.func = null;
- this.funcIcon = null;
-
- this.on('mount', () => {
- this.stream.on('read_all_messaging_messages', this.onReadAllMessagingMessages);
- this.stream.on('unread_messaging_message', this.onUnreadMessagingMessage);
-
- // Fetch count of unread messaging messages
- this.api('messaging/unread').then(res => {
- if (res.count > 0) {
- this.update({
- hasUnreadMessagingMessages: true
- });
- }
- });
- });
-
- this.on('unmount', () => {
- this.stream.off('read_all_messaging_messages', this.onReadAllMessagingMessages);
- this.stream.off('unread_messaging_message', this.onUnreadMessagingMessage);
-
- ui.off('title', this.setTitle);
- ui.off('func', this.setFunc);
- });
-
- this.onReadAllMessagingMessages = () => {
- this.update({
- hasUnreadMessagingMessages: false
- });
- };
-
- this.onUnreadMessagingMessage = () => {
- this.update({
- hasUnreadMessagingMessages: true
- });
- };
-
- this.setTitle = title => {
- this.refs.title.innerHTML = title;
- };
-
- this.setFunc = (fn, icon) => {
- this.update({
- func: fn,
- funcIcon: icon
- });
- };
-
- ui.on('title', this.setTitle);
- ui.on('func', this.setFunc);
- </script>
-</mk-ui-header>
diff --git a/src/web/app/mobile/tags/ui-nav.tag b/src/web/app/mobile/tags/ui-nav.tag
deleted file mode 100644
index 34235ba4f1..0000000000
--- a/src/web/app/mobile/tags/ui-nav.tag
+++ /dev/null
@@ -1,170 +0,0 @@
-<mk-ui-nav>
- <div class="backdrop" onclick={ parent.toggleDrawer }></div>
- <div class="body">
- <a class="me" if={ SIGNIN } href={ '/' + I.username }>
- <img class="avatar" src={ I.avatar_url + '?thumbnail&size=128' } alt="avatar"/>
- <p class="name">{ I.name }</p>
- </a>
- <div class="links">
- <ul>
- <li><a href="/"><i class="fa fa-home"></i>%i18n:mobile.tags.mk-ui-nav.home%<i class="fa fa-angle-right"></i></a></li>
- <li><a href="/i/notifications"><i class="fa fa-bell-o"></i>%i18n:mobile.tags.mk-ui-nav.notifications%<i class="fa fa-angle-right"></i></a></li>
- <li><a href="/i/messaging"><i class="fa fa-comments-o"></i>%i18n:mobile.tags.mk-ui-nav.messaging%<i class="i fa fa-circle" if={ hasUnreadMessagingMessages }></i><i class="fa fa-angle-right"></i></a></li>
- </ul>
- <ul>
- <li><a onclick={ search }><i class="fa fa-search"></i>%i18n:mobile.tags.mk-ui-nav.search%<i class="fa fa-angle-right"></i></a></li>
- </ul>
- <ul>
- <li><a href="/i/drive"><i class="fa fa-cloud"></i>%i18n:mobile.tags.mk-ui-nav.drive%<i class="fa fa-angle-right"></i></a></li>
- </ul>
- <ul>
- <li><a href="/i/settings"><i class="fa fa-cog"></i>%i18n:mobile.tags.mk-ui-nav.settings%<i class="fa fa-angle-right"></i></a></li>
- </ul>
- </div>
- <a href={ CONFIG.aboutUrl }><p class="about">%i18n:mobile.tags.mk-ui-nav.about%</p></a>
- </div>
- <style>
- :scope
- display none
-
- .backdrop
- position fixed
- top 0
- left 0
- z-index 1025
- width 100%
- height 100%
- background rgba(0, 0, 0, 0.2)
-
- .body
- position fixed
- top 0
- left 0
- z-index 1026
- width 240px
- height 100%
- overflow auto
- -webkit-overflow-scrolling touch
- color #777
- background #fff
-
- .me
- display block
- margin 0
- padding 16px
-
- .avatar
- display inline
- max-width 64px
- border-radius 32px
- vertical-align middle
-
- .name
- display block
- margin 0 16px
- position absolute
- top 0
- left 80px
- padding 0
- width calc(100% - 112px)
- color #777
- line-height 96px
- overflow hidden
- text-overflow ellipsis
- white-space nowrap
-
- ul
- display block
- margin 16px 0
- padding 0
- list-style none
-
- &:first-child
- margin-top 0
-
- li
- display block
- font-size 1em
- line-height 1em
-
- a
- display block
- padding 0 20px
- line-height 3rem
- line-height calc(1rem + 30px)
- color #777
- text-decoration none
-
- > i:first-child
- margin-right 0.5em
-
- > .i
- margin-left 6px
- vertical-align super
- font-size 10px
- color $theme-color
-
- > i:last-child
- position absolute
- top 0
- right 0
- padding 0 20px
- font-size 1.2em
- line-height calc(1rem + 30px)
- color #ccc
-
- .about
- margin 0
- padding 1em 0
- text-align center
- font-size 0.8em
- opacity 0.5
-
- a
- color #777
-
- </style>
- <script>
- this.mixin('i');
- this.mixin('page');
- this.mixin('api');
- this.mixin('stream');
-
- this.on('mount', () => {
- this.stream.on('read_all_messaging_messages', this.onReadAllMessagingMessages);
- this.stream.on('unread_messaging_message', this.onUnreadMessagingMessage);
-
- // Fetch count of unread messaging messages
- this.api('messaging/unread').then(res => {
- if (res.count > 0) {
- this.update({
- hasUnreadMessagingMessages: true
- });
- }
- });
- });
-
- this.on('unmount', () => {
- this.stream.off('read_all_messaging_messages', this.onReadAllMessagingMessages);
- this.stream.off('unread_messaging_message', this.onUnreadMessagingMessage);
- });
-
- this.onReadAllMessagingMessages = () => {
- this.update({
- hasUnreadMessagingMessages: false
- });
- };
-
- this.onUnreadMessagingMessage = () => {
- this.update({
- hasUnreadMessagingMessages: true
- });
- };
-
- this.search = () => {
- const query = window.prompt('%i18n:mobile.tags.mk-ui-nav.search%');
- if (query == null || query == '') return;
- this.page('/search:' + query);
- };
- </script>
-</mk-ui-nav>
diff --git a/src/web/app/mobile/tags/ui.tag b/src/web/app/mobile/tags/ui.tag
index 9d9cd4d74a..b2d96f6b8b 100644
--- a/src/web/app/mobile/tags/ui.tag
+++ b/src/web/app/mobile/tags/ui.tag
@@ -30,9 +30,378 @@
};
this.onStreamNotification = notification => {
+ // TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
+ this.stream.send({
+ type: 'read_notification',
+ id: notification.id
+ });
+
riot.mount(document.body.appendChild(document.createElement('mk-notify')), {
notification: notification
});
};
</script>
</mk-ui>
+
+<mk-ui-header>
+ <mk-special-message/>
+ <div class="main">
+ <div class="backdrop"></div>
+ <div class="content">
+ <button class="nav" onclick={ parent.toggleDrawer }><i class="fa fa-bars"></i></button>
+ <i class="fa fa-circle" if={ hasUnreadNotifications || hasUnreadMessagingMessages }></i>
+ <h1 ref="title">Misskey</h1>
+ <button if={ func } onclick={ func }><i class="fa fa-{ funcIcon }"></i></button>
+ </div>
+ </div>
+ <style>
+ :scope
+ $height = 48px
+
+ display block
+ position fixed
+ top 0
+ z-index 1024
+ width 100%
+ box-shadow 0 1px 0 rgba(#000, 0.075)
+
+ > .main
+ color rgba(#fff, 0.9)
+
+ > .backdrop
+ position absolute
+ top 0
+ z-index 1023
+ width 100%
+ height $height
+ -webkit-backdrop-filter blur(12px)
+ backdrop-filter blur(12px)
+ background-color rgba(#1b2023, 0.75)
+
+ > .content
+ z-index 1024
+
+ > h1
+ display block
+ margin 0 auto
+ padding 0
+ width 100%
+ max-width calc(100% - 112px)
+ text-align center
+ font-size 1.1em
+ font-weight normal
+ line-height $height
+ white-space nowrap
+ overflow hidden
+ text-overflow ellipsis
+
+ > i
+ > .icon
+ margin-right 8px
+
+ > img
+ display inline-block
+ vertical-align bottom
+ width ($height - 16px)
+ height ($height - 16px)
+ margin 8px
+ border-radius 6px
+
+ > .nav
+ display block
+ position absolute
+ top 0
+ left 0
+ width $height
+ font-size 1.4em
+ line-height $height
+ border-right solid 1px rgba(#000, 0.1)
+
+ > i
+ transition all 0.2s ease
+
+ > i
+ position absolute
+ top 8px
+ left 8px
+ pointer-events none
+ font-size 10px
+ color $theme-color
+
+ > button:last-child
+ display block
+ position absolute
+ top 0
+ right 0
+ width $height
+ text-align center
+ font-size 1.4em
+ color inherit
+ line-height $height
+ border-left solid 1px rgba(#000, 0.1)
+
+ </style>
+ <script>
+ import ui from '../scripts/ui-event';
+
+ this.mixin('api');
+ this.mixin('stream');
+
+ this.func = null;
+ this.funcIcon = null;
+
+ this.on('mount', () => {
+ this.stream.on('read_all_notifications', this.onReadAllNotifications);
+ this.stream.on('read_all_messaging_messages', this.onReadAllMessagingMessages);
+ this.stream.on('unread_messaging_message', this.onUnreadMessagingMessage);
+
+ // Fetch count of unread notifications
+ this.api('notifications/get_unread_count').then(res => {
+ if (res.count > 0) {
+ this.update({
+ hasUnreadNotifications: true
+ });
+ }
+ });
+
+ // Fetch count of unread messaging messages
+ this.api('messaging/unread').then(res => {
+ if (res.count > 0) {
+ this.update({
+ hasUnreadMessagingMessages: true
+ });
+ }
+ });
+ });
+
+ this.on('unmount', () => {
+ this.stream.off('read_all_notifications', this.onReadAllNotifications);
+ this.stream.off('read_all_messaging_messages', this.onReadAllMessagingMessages);
+ this.stream.off('unread_messaging_message', this.onUnreadMessagingMessage);
+
+ ui.off('title', this.setTitle);
+ ui.off('func', this.setFunc);
+ });
+
+ this.onReadAllNotifications = () => {
+ this.update({
+ hasUnreadNotifications: false
+ });
+ };
+
+ this.onReadAllMessagingMessages = () => {
+ this.update({
+ hasUnreadMessagingMessages: false
+ });
+ };
+
+ this.onUnreadMessagingMessage = () => {
+ this.update({
+ hasUnreadMessagingMessages: true
+ });
+ };
+
+ this.setTitle = title => {
+ this.refs.title.innerHTML = title;
+ };
+
+ this.setFunc = (fn, icon) => {
+ this.update({
+ func: fn,
+ funcIcon: icon
+ });
+ };
+
+ ui.on('title', this.setTitle);
+ ui.on('func', this.setFunc);
+ </script>
+</mk-ui-header>
+
+<mk-ui-nav>
+ <div class="backdrop" onclick={ parent.toggleDrawer }></div>
+ <div class="body">
+ <a class="me" if={ SIGNIN } href={ '/' + I.username }>
+ <img class="avatar" src={ I.avatar_url + '?thumbnail&size=128' } alt="avatar"/>
+ <p class="name">{ I.name }</p>
+ </a>
+ <div class="links">
+ <ul>
+ <li><a href="/"><i class="fa fa-home"></i>%i18n:mobile.tags.mk-ui-nav.home%<i class="fa fa-angle-right"></i></a></li>
+ <li><a href="/i/notifications"><i class="fa fa-bell-o"></i>%i18n:mobile.tags.mk-ui-nav.notifications%<i class="i fa fa-circle" if={ hasUnreadNotifications }></i><i class="fa fa-angle-right"></i></a></li>
+ <li><a href="/i/messaging"><i class="fa fa-comments-o"></i>%i18n:mobile.tags.mk-ui-nav.messaging%<i class="i fa fa-circle" if={ hasUnreadMessagingMessages }></i><i class="fa fa-angle-right"></i></a></li>
+ </ul>
+ <ul>
+ <li><a href={ CONFIG.chUrl } target="_blank"><i class="fa fa-television"></i>%i18n:mobile.tags.mk-ui-nav.ch%<i class="fa fa-angle-right"></i></a></li>
+ <li><a href="/i/drive"><i class="fa fa-cloud"></i>%i18n:mobile.tags.mk-ui-nav.drive%<i class="fa fa-angle-right"></i></a></li>
+ </ul>
+ <ul>
+ <li><a onclick={ search }><i class="fa fa-search"></i>%i18n:mobile.tags.mk-ui-nav.search%<i class="fa fa-angle-right"></i></a></li>
+ </ul>
+ <ul>
+ <li><a href="/i/settings"><i class="fa fa-cog"></i>%i18n:mobile.tags.mk-ui-nav.settings%<i class="fa fa-angle-right"></i></a></li>
+ </ul>
+ </div>
+ <a href={ CONFIG.aboutUrl }><p class="about">%i18n:mobile.tags.mk-ui-nav.about%</p></a>
+ </div>
+ <style>
+ :scope
+ display none
+
+ .backdrop
+ position fixed
+ top 0
+ left 0
+ z-index 1025
+ width 100%
+ height 100%
+ background rgba(0, 0, 0, 0.2)
+
+ .body
+ position fixed
+ top 0
+ left 0
+ z-index 1026
+ width 240px
+ height 100%
+ overflow auto
+ -webkit-overflow-scrolling touch
+ color #777
+ background #fff
+
+ .me
+ display block
+ margin 0
+ padding 16px
+
+ .avatar
+ display inline
+ max-width 64px
+ border-radius 32px
+ vertical-align middle
+
+ .name
+ display block
+ margin 0 16px
+ position absolute
+ top 0
+ left 80px
+ padding 0
+ width calc(100% - 112px)
+ color #777
+ line-height 96px
+ overflow hidden
+ text-overflow ellipsis
+ white-space nowrap
+
+ ul
+ display block
+ margin 16px 0
+ padding 0
+ list-style none
+
+ &:first-child
+ margin-top 0
+
+ li
+ display block
+ font-size 1em
+ line-height 1em
+
+ a
+ display block
+ padding 0 20px
+ line-height 3rem
+ line-height calc(1rem + 30px)
+ color #777
+ text-decoration none
+
+ > i:first-child
+ margin-right 0.5em
+
+ > .i
+ margin-left 6px
+ vertical-align super
+ font-size 10px
+ color $theme-color
+
+ > i:last-child
+ position absolute
+ top 0
+ right 0
+ padding 0 20px
+ font-size 1.2em
+ line-height calc(1rem + 30px)
+ color #ccc
+
+ .about
+ margin 0
+ padding 1em 0
+ text-align center
+ font-size 0.8em
+ opacity 0.5
+
+ a
+ color #777
+
+ </style>
+ <script>
+ this.mixin('i');
+ this.mixin('page');
+ this.mixin('api');
+ this.mixin('stream');
+
+ this.on('mount', () => {
+ this.stream.on('read_all_notifications', this.onReadAllNotifications);
+ this.stream.on('read_all_messaging_messages', this.onReadAllMessagingMessages);
+ this.stream.on('unread_messaging_message', this.onUnreadMessagingMessage);
+
+ // Fetch count of unread notifications
+ this.api('notifications/get_unread_count').then(res => {
+ if (res.count > 0) {
+ this.update({
+ hasUnreadNotifications: true
+ });
+ }
+ });
+
+ // Fetch count of unread messaging messages
+ this.api('messaging/unread').then(res => {
+ if (res.count > 0) {
+ this.update({
+ hasUnreadMessagingMessages: true
+ });
+ }
+ });
+ });
+
+ this.on('unmount', () => {
+ this.stream.off('read_all_notifications', this.onReadAllNotifications);
+ this.stream.off('read_all_messaging_messages', this.onReadAllMessagingMessages);
+ this.stream.off('unread_messaging_message', this.onUnreadMessagingMessage);
+ });
+
+ this.onReadAllNotifications = () => {
+ this.update({
+ hasUnreadNotifications: false
+ });
+ };
+
+ this.onReadAllMessagingMessages = () => {
+ this.update({
+ hasUnreadMessagingMessages: false
+ });
+ };
+
+ this.onUnreadMessagingMessage = () => {
+ this.update({
+ hasUnreadMessagingMessages: true
+ });
+ };
+
+ this.search = () => {
+ const query = window.prompt('%i18n:mobile.tags.mk-ui-nav.search%');
+ if (query == null || query == '') return;
+ this.page('/search:' + query);
+ };
+ </script>
+</mk-ui-nav>
diff --git a/src/web/app/reset.styl b/src/web/app/reset.styl
index 85bbd11473..3d4b06dbdf 100644
--- a/src/web/app/reset.styl
+++ b/src/web/app/reset.styl
@@ -1,16 +1,3 @@
-*
- position relative
- box-sizing border-box
- background-clip padding-box !important
-
-html
-body
- margin 0
- padding 0
-
-body
- overflow-wrap break-word
-
input:not([type])
input[type='text']
input[type='password']
diff --git a/src/web/app/stats/style.styl b/src/web/app/stats/style.styl
index b48d7aeb9e..5ae230ea56 100644
--- a/src/web/app/stats/style.styl
+++ b/src/web/app/stats/style.styl
@@ -1,4 +1,5 @@
-@import "../base"
+@import "../app"
+@import "../reset"
html
color #456267
diff --git a/src/web/app/status/style.styl b/src/web/app/status/style.styl
index b48d7aeb9e..5ae230ea56 100644
--- a/src/web/app/status/style.styl
+++ b/src/web/app/status/style.styl
@@ -1,4 +1,5 @@
-@import "../base"
+@import "../app"
+@import "../reset"
html
color #456267