This commit is contained in:
syuilo 2017-02-21 20:34:54 +09:00
parent 8647c1d71c
commit 2de118a45d
15 changed files with 243 additions and 303 deletions

View file

@ -55,21 +55,23 @@
this.fetching = true; this.fetching = true;
this.on('mount', () => { this.on('mount', () => {
this.api 'i/signin_history' this.api('i/signin_history').then(history => {
}).then((history) => { this.update({
this.history = history fetching: false,
this.fetching = false history: history
this.update(); });
.catch (err) => });
console.error err
this.stream.on 'signin' this.on-signin this.stream.on('signin', this.onSignin);
});
this.on('unmount', () => { this.on('unmount', () => {
this.stream.off 'signin' this.on-signin this.stream.off('signin', this.onSignin);
});
this.on-signin = (signin) => { this.onSignin = signin => {
@history.unshift signin this.history.unshift(signin);
this.update(); this.update();
};
</script> </script>
</mk-signin-history> </mk-signin-history>

View file

@ -1,6 +1,6 @@
<mk-following-setuper> <mk-following-setuper>
<p class="title">気になるユーザーをフォロー:</p> <p class="title">気になるユーザーをフォロー:</p>
<div class="users" if={ !loading && users.length > 0 }> <div class="users" if={ !fetching && users.length > 0 }>
<div class="user" each={ users }><a class="avatar-anchor" href={ CONFIG.url + '/' + username }><img class="avatar" src={ avatar_url + '?thumbnail&size=42' } alt="" data-user-preview={ id }/></a> <div class="user" each={ users }><a class="avatar-anchor" href={ CONFIG.url + '/' + username }><img class="avatar" src={ avatar_url + '?thumbnail&size=42' } alt="" data-user-preview={ id }/></a>
<div class="body"><a class="name" href={ CONFIG.url + '/' + username } target="_blank" data-user-preview={ id }>{ name }</a> <div class="body"><a class="name" href={ CONFIG.url + '/' + username } target="_blank" data-user-preview={ id }>{ name }</a>
<p class="username">@{ username }</p> <p class="username">@{ username }</p>
@ -8,8 +8,8 @@
<mk-follow-button user={ this }></mk-follow-button> <mk-follow-button user={ this }></mk-follow-button>
</div> </div>
</div> </div>
<p class="empty" if={ !loading && users.length == 0 }>おすすめのユーザーは見つかりませんでした。</p> <p class="empty" if={ !fetching && users.length == 0 }>おすすめのユーザーは見つかりませんでした。</p>
<p class="loading" if={ loading }><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます <p class="fetching" if={ fetching }><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます
<mk-ellipsis></mk-ellipsis> <mk-ellipsis></mk-ellipsis>
</p><a class="refresh" onclick={ refresh }>もっと見る</a> </p><a class="refresh" onclick={ refresh }>もっと見る</a>
<button class="close" onclick={ close } title="閉じる"><i class="fa fa-times"></i></button> <button class="close" onclick={ close } title="閉じる"><i class="fa fa-times"></i></button>
@ -81,7 +81,7 @@
text-align center text-align center
color #aaa color #aaa
> .loading > .fetching
margin 0 margin 0
padding 16px padding 16px
text-align center text-align center
@ -126,38 +126,46 @@
this.mixin('api'); this.mixin('api');
this.mixin('user-preview'); this.mixin('user-preview');
this.users = null this.users = null;
this.loading = true this.fetching = true;
this.limit = 6users this.limit = 6;
this.page = 0 this.page = 0;
this.on('mount', () => { this.on('mount', () => {
this.load(); this.fetch();
});
this.load = () => { this.fetch = () => {
this.loading = true this.update({
this.users = null fetching: true,
this.update(); users: null
});
this.api('users/recommendation', { this.api('users/recommendation', {
limit: @limit limit: this.limit,
offset: @limit * this.page offset: this.limit * this.page
}).then((users) => { }).then(users => {
this.loading = false this.fetching = false
this.users = users this.users = users
this.update(); this.update({
.catch (err, text-status) -> fetching: false,
console.error err users: users
});
});
};
this.refresh = () => { this.refresh = () => {
if this.users.length < @limit if (this.users.length < this.limit) {
this.page = 0 this.page = 0;
else } else {
this.page++ this.page++;
this.load(); }
this.fetch();
};
this.close = () => { this.close = () => {
this.unmount(); this.unmount();
};
</script> </script>
</mk-following-setuper> </mk-following-setuper>

View file

@ -35,41 +35,26 @@
</style> </style>
<script> <script>
this.image = this.opts.image this.image = this.opts.image;
this.on('mount', () => { this.on('mount', () => {
Velocity(this.root, { Velocity(this.root, {
opacity: 1 opacity: 1
}, { }, {
duration: 100ms duration: 100,
easing: 'linear' easing: 'linear'
} });
});
#Velocity(@img, {
// scale: 1
// opacity: 1
#}, {
// duration: 200ms
// easing: 'ease-out'
#}
this.close = () => { this.close = () => {
Velocity(this.root, { Velocity(this.root, {
opacity: 0 opacity: 0
}, { }, {
duration: 100ms duration: 100,
easing: 'linear' easing: 'linear',
complete: => this.unmount(); complete: () => this.unmount()
} });
};
#Velocity(@img, {
// scale: 0.9
// opacity: 0
#}, {
// duration: 200ms
// easing: 'ease-in'
// complete: =>
// this.unmount();
#}
</script> </script>
</mk-image-dialog> </mk-image-dialog>

View file

@ -26,20 +26,22 @@
</style> </style>
<script> <script>
this.images = this.opts.images this.images = this.opts.images;
this.image = @images.0 this.image = this.images[0];
this.mousemove = (e) => { this.mousemove = e => {
rect = this.refs.view.getBoundingClientRect(); const rect = this.refs.view.getBoundingClientRect();
mouse-x = e.client-x - rect.left const mouseX = e.clientX - rect.left;
mouse-y = e.client-y - rect.top const mouseY = e.clientY - rect.top;
xp = mouse-x / this.refs.view.offset-width * 100 const xp = mouseX / this.refs.view.offsetWidth * 100;
yp = mouse-y / this.refs.view.offset-height * 100 const yp = mouseY / this.refs.view.offsetHeight * 100;
this.refs.view.style.background-position = xp + '% ' + yp + '%' this.refs.view.style.backgroundPosition = xp + '% ' + yp + '%';
};
this.click = () => { this.click = () => {
dialog = document.body.appendChild(document.createElement('mk-image-dialog')); riot.mount(document.body.appendChild(document.createElement('mk-image-dialog')), {
riot.mount dialog, do image: this.image
image: @image });
};
</script> </script>
</mk-images-viewer> </mk-images-viewer>

View file

@ -182,32 +182,36 @@
this.mixin('user-preview'); this.mixin('user-preview');
this.mixin('get-post-summary'); this.mixin('get-post-summary');
this.notifications = [] this.notifications = [];
this.loading = true this.loading = true;
this.on('mount', () => { this.on('mount', () => {
this.api 'i/notifications' this.api('i/notifications').then(notifications => {
}).then((notifications) => { this.update({
this.notifications = notifications loading: false,
this.loading = false notifications: notifications
this.update(); });
.catch (err, text-status) -> });
console.error err
this.stream.on 'notification' this.on-notification this.stream.on('notification', this.onNotification);
});
this.on('unmount', () => { this.on('unmount', () => {
this.stream.off 'notification' this.on-notification this.stream.off('notification', this.onNotification);
});
this.on-notification = (notification) => { this.onNotification = notification => {
@notifications.unshift notification this.notifications.unshift(notification);
this.update(); this.update();
};
this.on('update', () => { this.on('update', () => {
@notifications.forEach (notification) => this.notifications.forEach(notification => {
date = (new Date notification.created_at).getDate() const date = new Date(notification.created_at).getDate();
month = (new Date notification.created_at).getMonth() + 1 const month = new Date(notification.created_at).getMonth() + 1;
notification._date = date notification._date = date;
notification._datetext = month + '月 ' + date + '日' notification._datetext = `${month}月 ${date}日`;
});
});
</script> </script>
</mk-notifications> </mk-notifications>

View file

@ -108,33 +108,40 @@
this.mixin('date-stringify'); this.mixin('date-stringify');
this.mixin('user-preview'); this.mixin('user-preview');
this.post = this.opts.post this.post = this.opts.post;
this.url = CONFIG.url + '/' + this.post.user.username + '/' + this.post.id this.url = CONFIG.url + '/' + this.post.user.username + '/' + this.post.id;
this.title = @date-stringify this.post.created_at this.title = this.dateStringify(this.post.created_at);
this.on('mount', () => { this.on('mount', () => {
if this.post.text? if (this.p.text) {
tokens = @analyze this.post.text const tokens = this.analyze(this.p.text);
this.refs.text.innerHTML = @compile tokens
this.refs.text.children.forEach (e) => this.refs.text.innerHTML = this.refs.text.innerHTML.replace('<p class="dummy"></p>', this.compile(tokens));
if e.tag-name == 'MK-URL'
riot.mount e this.refs.text.children.forEach(e => {
if (e.tagName == 'MK-URL') riot.mount(e);
});
}
});
this.like = () => { this.like = () => {
if this.post.is_liked if (this.post.is_liked) {
this.api('posts/likes/delete', { this.api('posts/likes/delete', {
post_id: this.post.id post_id: this.post.id
}).then(() => { }).then(() => {
this.post.is_liked = false this.post.is_liked = false;
this.update(); this.update();
else });
} else {
this.api('posts/likes/create', { this.api('posts/likes/create', {
post_id: this.post.id post_id: this.post.id
}).then(() => { }).then(() => {
this.post.is_liked = true this.post.is_liked = true;
this.update(); this.update();
});
}
};
</script> </script>
</mk-post-detail-sub> </mk-post-detail-sub>

View file

@ -335,102 +335,120 @@
this.mixin('date-stringify'); this.mixin('date-stringify');
this.mixin('NotImplementedException'); this.mixin('NotImplementedException');
this.fetching = true this.fetching = true;
this.loading-context = false this.loadingContext = false;
this.content = null this.content = null;
this.post = null this.post = null;
this.on('mount', () => { this.on('mount', () => {
this.api('posts/show', { this.api('posts/show', {
post_id: this.opts.post post_id: this.opts.post
}).then((post) => { }).then(post => {
this.fetching = false const isRepost = post.repost != null;
this.post = post const p = isRepost ? post.repost : post;
this.update({
fetching: false,
post: post,
isRepost: isRepost,
p: p,
title: this.dateStringify(p.created_at)
});
this.trigger('loaded'); this.trigger('loaded');
this.is-repost = this.post.repost? if (this.p.text) {
this.p = if @is-repost then this.post.repost else this.post const tokens = this.analyze(this.p.text);
this.title = @date-stringify this.p.created_at this.refs.text.innerHTML = this.compile(tokens);
this.update(); this.refs.text.children.forEach(e => {
if (e.tagName == 'MK-URL') riot.mount(e);
if this.p.text? });
tokens = @analyze this.p.text
this.refs.text.innerHTML = @compile tokens
this.refs.text.children.forEach (e) =>
if e.tag-name == 'MK-URL'
riot.mount e
// URLをプレビュー // URLをプレビュー
tokens tokens
.filter (t) -> t.type == 'link' .filter(t => t.type == 'link')
.map (t) => .map(t => {
this.preview = this.refs.text.appendChild(document.createElement('mk-url-preview')); riot.mount(this.refs.text.appendChild(document.createElement('mk-url-preview')), {
riot.mount this.preview, do
url: t.content url: t.content
});
});
}
// Get likes // Get likes
this.api('posts/likes', { this.api('posts/likes', {
post_id: this.p.id post_id: this.p.id,
limit: 8 limit: 8
}).then((likes) => { }).then(likes => {
this.likes = likes this.update({
this.update(); likes: likes
});
});
// Get reposts // Get reposts
this.api('posts/reposts', { this.api('posts/reposts', {
post_id: this.p.id post_id: this.p.id,
limit: 8 limit: 8
}).then((reposts) => { }).then(reposts => {
this.reposts = reposts this.update({
this.update(); reposts: reposts
});
});
// Get replies // Get replies
this.api('posts/replies', { this.api('posts/replies', {
post_id: this.p.id post_id: this.p.id,
limit: 8 limit: 8
}).then((replies) => { }).then(replies => {
this.replies = replies this.update({
this.update(); replies: replies
});
this.update(); });
});
});
this.reply = () => { this.reply = () => {
form = document.body.appendChild(document.createElement('mk-post-form-window')); riot.mount(document.body.appendChild(document.createElement('mk-post-form-window')), {
riot.mount form, do
reply: this.p reply: this.p
});
};
this.repost = () => { this.repost = () => {
form = document.body.appendChild(document.createElement('mk-repost-form-window')); riot.mount(document.body.appendChild(document.createElement('mk-repost-form-window')), {
riot.mount form, do
post: this.p post: this.p
});
};
this.like = () => { this.like = () => {
if this.p.is_liked if (this.p.is_liked) {
this.api('posts/likes/delete', { this.api('posts/likes/delete', {
post_id: this.p.id post_id: this.p.id
}).then(() => { }).then(() => {
this.p.is_liked = false this.p.is_liked = false;
this.update(); this.update();
else });
} else {
this.api('posts/likes/create', { this.api('posts/likes/create', {
post_id: this.p.id post_id: this.p.id
}).then(() => { }).then(() => {
this.p.is_liked = true this.p.is_liked = true;
this.update(); this.update();
});
}
};
this.load-context = () => { this.loadContext = () => {
this.loading-context = true this.loadingContext = true;
// Get context // Fetch context
this.api('posts/context', { this.api('posts/context', {
post_id: this.p.reply_to_id post_id: this.p.reply_to_id
}).then((context) => { }).then(context => {
this.context = context.reverse! this.update({
this.loading-context = false loadContext: false,
this.update(); content: context.reverse()
});
});
};
</script> </script>
</mk-post-detail> </mk-post-detail>

View file

@ -32,24 +32,31 @@
</style> </style>
<script> <script>
this.uploading-files = [] this.uploadingFiles = [];
this.files = [] this.files = [];
this.on('mount', () => { this.on('mount', () => {
this.refs.window.refs.form.focus(); this.refs.window.refs.form.focus();
this.refs.window.on('closed', () => { this.refs.window.on('closed', () => {
this.unmount(); this.unmount();
});
this.refs.window.refs.form.on('post', () => { this.refs.window.refs.form.on('post', () => {
this.refs.window.close(); this.refs.window.close();
});
this.refs.window.refs.form.on('change-uploading-files', (files) => { this.refs.window.refs.form.on('change-uploading-files', files => {
this.uploading-files = files this.update({
this.update(); uploadingFiles: files
});
});
this.refs.window.refs.form.on('change-files', (files) => { this.refs.window.refs.form.on('change-files', files => {
this.files = files this.update({
this.update(); files: files
});
});
});
</script> </script>
</mk-post-form-window> </mk-post-form-window>

View file

@ -86,8 +86,8 @@
this.mixin('date-stringify'); this.mixin('date-stringify');
this.mixin('user-preview'); this.mixin('user-preview');
this.post = this.opts.post this.post = this.opts.post;
this.title = @date-stringify this.post.created_at this.title = this.dateStringify(this.post.created_at);
</script> </script>
</mk-post-preview> </mk-post-preview>

View file

@ -75,20 +75,25 @@
</style> </style>
<script> <script>
this.title = this.opts.title this.title = this.opts.title;
this.value = parse-int this.opts.value, 10 this.value = parseInt(this.opts.value, 10);
this.max = parse-int this.opts.max, 10 this.max = parseInt(this.opts.max, 10);
this.on('mount', () => { this.on('mount', () => {
this.refs.window.on('closed', () => { this.refs.window.on('closed', () => {
this.unmount(); this.unmount();
});
});
this.update-progress = (value, max) => { this.updateProgress = (value, max) => {
this.value = parse-int value, 10 this.update({
this.max = parse-int max, 10 value: parseInt(value, 10),
this.update(); max: parseInt(max, 10)
});
};
this.close = () => { this.close = () => {
this.refs.window.close(); this.refs.window.close();
};
</script> </script>
</mk-progress-dialog> </mk-progress-dialog>

View file

@ -12,25 +12,32 @@
</style> </style>
<script> <script>
this.on-document-keydown = (e) => { this.onDocumentKeydown = e => {
tag = e.target.tag-name.to-lower-case! if (e.target.tagName != 'INPUT' && e.target.tagName != 'TEXTAREA') {
if tag != 'input' and tag != 'textarea' if (e.which == 27) { // Esc
if e.which == 27 // Esc
this.refs.window.close(); this.refs.window.close();
}
}
};
this.on('mount', () => { this.on('mount', () => {
this.refs.window.refs.form.on('cancel', () => { this.refs.window.refs.form.on('cancel', () => {
this.refs.window.close(); this.refs.window.close();
});
this.refs.window.refs.form.on('posted', () => { this.refs.window.refs.form.on('posted', () => {
this.refs.window.close(); this.refs.window.close();
});
document.addEventListener 'keydown' this.on-document-keydown document.addEventListener('keydown', this.onDocumentKeydown);
this.refs.window.on('closed', () => { this.refs.window.on('closed', () => {
this.unmount(); this.unmount();
});
});
this.on('unmount', () => { this.on('unmount', () => {
document.removeEventListener 'keydown' this.on-document-keydown document.removeEventListener('keydown', this.onDocumentKeydown);
});
</script> </script>
</mk-repost-form-window> </mk-repost-form-window>

View file

@ -117,28 +117,31 @@
this.mixin('api'); this.mixin('api');
this.mixin('notify'); this.mixin('notify');
this.wait = false this.wait = false;
this.quote = false this.quote = false;
this.cancel = () => { this.cancel = () => {
this.trigger('cancel'); this.trigger('cancel');
};
this.ok = () => { this.ok = () => {
this.wait = true this.wait = true;
this.api('posts/create', { this.api('posts/create', {
repost_id: this.opts.post.id repost_id: this.opts.post.id,
text: if this.quote then this.refs.text.value else undefined text: this.quote ? this.refs.text.value : undefined
}).then((data) => { }).then(data => {
this.trigger('posted'); this.trigger('posted');
@notify 'Repostしました' this.notify('Repostしました');
.catch (err) => }).catch(err => {
console.error err this.notify('Repostできませんでした');
@notify 'Repostできませんでした'
}).then(() => { }).then(() => {
this.wait = false this.update({
this.update(); wait: false
});
});
this.onquote = () => { this.onquote = () => {
this.quote = true this.quote = true;
};
</script> </script>
</mk-repost-form> </mk-repost-form>

View file

@ -31,6 +31,7 @@
if (e.which == 80 || e.which == 78) { // p or n if (e.which == 80 || e.which == 78) { // p or n
e.preventDefault(); e.preventDefault();
this.openPostForm(); this.openPostForm();
}
}; };
</script> </script>
</mk-ui> </mk-ui>

View file

@ -1,67 +0,0 @@
<mk-user-friends-graph>
<canvas ref="canv" width="750" height="250"></canvas>
<style>
:scope
display block
width 750px
height 250px
</style>
<script>
this.mixin('api');
this.mixin('is-promise');
this.user = null
this.user-promise = if @is-promise this.opts.user then this.opts.user else Promise.resolve this.opts.user
this.on('mount', () => {
user <~ this.user-promise.then
this.user = user
this.update();
this.api('aggregation/users/followers', {
user_id: this.user.id
limit: 30days
}).then((followers) => {
followers = followers.reverse!
this.api('aggregation/users/following', {
user_id: this.user.id
limit: 30days
}).then((following) => {
following = following.reverse!
new Chart this.refs.canv, do
type: 'line'
data:
labels: following.map (x, i) => if i % 3 == 2 then x.date.day + '日' else ''
datasets: [
{
label: 'フォロー'
data: following.map (x) => x.count
line-tension: 0
border-width: 2
fill: true
background-color: 'rgba(127, 221, 64, 0.2)'
point-background-color: '#fff'
point-radius: 4
point-border-width: 2
border-color: '#7fdd40'
},
{
label: 'フォロワー'
data: followers.map (x) => x.count
line-tension: 0
border-width: 2
fill: true
background-color: 'rgba(255, 99, 132, 0.2)'
point-background-color: '#fff'
point-radius: 4
point-border-width: 2
border-color: '#FF6384'
}
]
options:
responsive: false
</script>
</mk-user-friends-graph>

View file

@ -1,42 +0,0 @@
<mk-user-likes-graph>
<canvas ref="canv" width="750" height="250"></canvas>
<style>
:scope
display block
width 750px
height 250px
</style>
<script>
this.mixin('api');
this.mixin('is-promise');
this.user = null
this.user-promise = if @is-promise this.opts.user then this.opts.user else Promise.resolve this.opts.user
this.on('mount', () => {
user <~ this.user-promise.then
this.user = user
this.update();
this.api('aggregation/users/like', {
user_id: this.user.id
limit: 30days
}).then((likes) => {
likes = likes.reverse!
new Chart this.refs.canv, do
type: 'bar'
data:
labels: likes.map (x, i) => if i % 3 == 2 then x.date.day + '日' else ''
datasets: [
{
label: 'いいねした数'
data: likes.map (x) => x.count
background-color: '#F7796C'
}
]
options:
responsive: false
</script>
</mk-user-likes-graph>