1
0
mirror of https://github.com/hotomoe/hotomoe synced 2024-11-25 07:36:24 +09:00
This commit is contained in:
syuilo 2017-01-12 05:55:38 +09:00
parent 8b273e215f
commit 520299c2b4
169 changed files with 14582 additions and 14865 deletions

View File

@ -189,231 +189,6 @@ gulp.task('build:client:scripts', done => {
.transform(ls)
.transform(aliasify, aliasifyConfig)
.transform(transformify((source, file) => {
if (file.substr(-4) !== '.tag') return source;
gutil.log('Build Tag: ' + file);
return source;
}))
// tagの{}の''を不要にする (その代わりスタイルの記法は使えなくなるけど)
.transform(transformify((source, file) => {
if (file.substr(-4) !== '.tag') return source;
const tag = new Tag(source);
const html = tag.sections.filter(s => s.name == 'html')[0];
html.lines = html.lines.map(line => {
if (line.replace(/\t/g, '')[0] === '|') {
return line;
} else {
return line.replace(/([+=])\s?\{(.+?)\}/g, '$1"{$2}"');
}
});
const styles = tag.sections.filter(s => s.name == 'style');
if (styles.length == 0) {
return tag.compile();
}
styles.forEach(style => {
let head = style.lines.shift();
head = head.replace(/([+=])\s?\{(.+?)\}/g, '$1"{$2}"');
style.lines.unshift(head);
});
return tag.compile();
}))
// tagの@hogeをref='hoge'にする
.transform(transformify((source, file) => {
if (file.substr(-4) !== '.tag') return source;
const tag = new Tag(source);
const html = tag.sections.filter(s => s.name == 'html')[0];
html.lines = html.lines.map(line => {
if (line.indexOf('@') === -1) {
return line;
} else if (line.replace(/\t/g, '')[0] === '|') {
return line;
} else {
while (line.match(/[^\s']@[a-z-]+/) !== null) {
const match = line.match(/@[a-z-]+/);
let name = match[0];
if (line[line.indexOf(name) + name.length] === '(') {
line = line.replace(name + '(', '(ref=\'' + camelCase(name.substr(1)) + '\',');
} else {
line = line.replace(name, '(ref=\'' + camelCase(name.substr(1)) + '\')');
}
}
return line;
}
});
return tag.compile();
function camelCase(str): string {
return str.replace(/-([^\s])/g, (match, group1) => {
return group1.toUpperCase();
});
}
}))
// tagのchain-caseをcamelCaseにする
.transform(transformify((source, file) => {
if (file.substr(-4) !== '.tag') return source;
const tag = new Tag(source);
const html = tag.sections.filter(s => s.name == 'html')[0];
html.lines = html.lines.map(line => {
(line.match(/\{.+?\}/g) || []).forEach(x => {
line = line.replace(x, camelCase(x));
});
return line;
});
return tag.compile();
function camelCase(str): string {
str = str.replace(/([a-z\-]+):/g, (match, group1) => {
return group1.replace(/\-/g, '###') + ':';
});
str = str.replace(/'(.+?)'/g, (match, group1) => {
return "'" + group1.replace(/\-/g, '###') + "'";
});
str = str.replace(/-([^\s0-9])/g, (match, group1) => {
return group1.toUpperCase();
});
str = str.replace(/###/g, '-');
return str;
}
}))
// tagのstyleの属性
.transform(transformify((source, file) => {
if (file.substr(-4) !== '.tag') return source;
const tag = new Tag(source);
const styles = tag.sections.filter(s => s.name == 'style');
if (styles.length == 0) {
return tag.compile();
}
styles.forEach(style => {
let head = style.lines.shift();
if (style.attr) {
style.attr = style.attr + ', type=\'stylus\', scoped';
} else {
style.attr = 'type=\'stylus\', scoped';
}
style.lines.unshift(head);
});
return tag.compile();
}))
// tagのstyleの定数
.transform(transformify((source, file) => {
if (file.substr(-4) !== '.tag') return source;
const tag = new Tag(source);
const styles = tag.sections.filter(s => s.name == 'style');
if (styles.length == 0) {
return tag.compile();
}
styles.forEach(style => {
const head = style.lines.shift();
style.lines.unshift('$theme-color = ' + config.themeColor);
style.lines.unshift('$theme-color-foreground = #fff');
style.lines.unshift(head);
});
return tag.compile();
}))
// tagのstyleを暗黙的に:scopeにする
.transform(transformify((source, file) => {
if (file.substr(-4) !== '.tag') return source;
const tag = new Tag(source);
const styles = tag.sections.filter(s => s.name == 'style');
if (styles.length == 0) {
return tag.compile();
}
styles.forEach((style, i) => {
if (i != 0) {
return;
}
const head = style.lines.shift();
style.lines = style.lines.map(line => {
return '\t' + line;
});
style.lines.unshift(':scope');
style.lines.unshift(head);
});
return tag.compile();
}))
// tagのtheme styleのパース
.transform(transformify((source, file) => {
if (file.substr(-4) !== '.tag') return source;
const tag = new Tag(source);
const styles = tag.sections.filter(s => s.name == 'style');
if (styles.length == 0) {
return tag.compile();
}
styles.forEach((style, i) => {
if (i == 0) {
return;
} else if (style.attr.substr(0, 6) != 'theme=') {
return;
}
const head = style.lines.shift();
style.lines = style.lines.map(line => {
return '\t' + line;
});
style.lines.unshift(':scope');
style.lines = style.lines.map(line => {
return '\t' + line;
});
style.lines.unshift('html[data-' + style.attr.match(/theme='(.+?)'/)[0] + ']');
style.lines.unshift(head);
});
return tag.compile();
}))
// tagのstyleおよびscriptのインデントを不要にする
.transform(transformify((source, file) => {
if (file.substr(-4) !== '.tag') return source;
const tag = new Tag(source);
tag.sections = tag.sections.map(section => {
if (section.name != 'html') {
section.indent++;
}
return section;
});
return tag.compile();
}))
// スペースでインデントされてないとエラーが出る
.transform(transformify((source, file) => {
if (file.substr(-4) !== '.tag') return source;
@ -423,6 +198,8 @@ gulp.task('build:client:scripts', done => {
.transform(transformify((source, file) => {
return source
.replace(/VERSION/g, `'${commit ? commit.hash : 'null'}'`)
.replace(/\$theme\-color\-foreground/g, '#fff')
.replace(/\$theme\-color/g, config.themeColor)
.replace(/CONFIG\.theme-color/g, `'${config.themeColor}'`)
.replace(/CONFIG\.themeColor/g, `'${config.themeColor}'`)
.replace(/CONFIG\.api\.url/g, `'${config.scheme}://api.${config.host}'`)
@ -435,7 +212,6 @@ gulp.task('build:client:scripts', done => {
}))
.transform(riotify, {
template: 'pug',
type: 'livescript',
expr: false,
compact: true,
@ -446,17 +222,6 @@ gulp.task('build:client:scripts', done => {
}
}
})
// Riotが謎の空白を挿入する
.transform(transformify((source, file) => {
if (file.substr(-4) !== '.tag') return source;
return source.replace(/\s<mk\-ellipsis>/g, '<mk-ellipsis>');
}))
/*
// LiveScruptがHTMLクラスのショートカットを変な風に生成するのでそれを修正
.transform(transformify((source, file) => {
if (file.substr(-4) !== '.tag') return source;
return source.replace(/class="\{\(\{(.+?)\}\)\}"/g, 'class="{$1}"');
}))*/
.bundle()
.pipe(source(entry.replace('./src/web/app/', './').replace('.ls', '.js')));
@ -531,87 +296,3 @@ gulp.task('build:client:pug', [
}))
.pipe(gulp.dest('./built/web/app/'));
});
class Tag {
sections: {
name: string;
attr?: string;
indent: number;
lines: string[];
}[];
constructor(source) {
this.sections = [];
source = source
.replace(/\r\n/g, '\n')
.replace(/\n(\t+?)\n/g, '\n')
.replace(/\n+/g, '\n');
const html = {
name: 'html',
indent: 0,
lines: []
};
let flag = false;
source.split('\n').forEach((line, i) => {
const indent = line.lastIndexOf('\t') + 1;
if (i != 0 && indent == 0) {
flag = true;
}
if (!flag) {
source = source.replace(/^.*?\n/, '');
html.lines.push(i == 0 ? line : line.substr(1));
}
});
this.sections.push(html);
while (source != '') {
const line = source.substr(0, source.indexOf('\n'));
const root = line.match(/^\t*([a-z]+)(\.|\()?/)[1];
const beginIndent = line.lastIndexOf('\t') + 1;
flag = false;
const section = {
name: root,
attr: (line.match(/\((.+?)\)/) || [null, null])[1],
indent: beginIndent,
lines: []
};
source.split('\n').forEach((line, i) => {
const currentIndent = line.lastIndexOf('\t') + 1;
if (i != 0 && (currentIndent == beginIndent || currentIndent == 0)) {
flag = true;
}
if (!flag) {
if (i == 0 && line[line.length - 1] == '.') {
line = line.substr(0, line.length - 1);
}
if (i == 0 && line.indexOf('(') != -1) {
line = line.substr(0, line.indexOf('('));
}
source = source.replace(/^.*?\n/, '');
section.lines.push(i == 0 ? line.substr(beginIndent) : line.substr(beginIndent + 1));
}
});
this.sections.push(section);
}
}
compile(): string {
let dist = '';
this.sections.forEach((section, j) => {
dist += section.lines.map((line, i) => {
if (i == 0) {
const attr = section.attr != null ? '(' + section.attr + ')' : '';
const tail = j != 0 ? '.' : '';
return '\t'.repeat(section.indent) + line + attr + tail;
} else {
return '\t'.repeat(section.indent + 1) + line;
}
}).join('\n') + '\n';
});
return dist;
}
}

View File

@ -1,126 +1,126 @@
mk-form
header
h1
i { app.name }
| があなたの
b アカウント
| に
b アクセス
| することを
b 許可
| しますか?
img(src={ app.icon_url + '?thumbnail&size=64' })
div.app
section
h2 { app.name }
p.nid { app.name_id }
p.description { app.description }
section
h2 このアプリは次の権限を要求しています:
ul
virtual(each={ p in app.permission })
li(if={ p == 'account-read' }) アカウントの情報を見る。
li(if={ p == 'account-write' }) アカウントの情報を操作する。
li(if={ p == 'post-write' }) 投稿する。
li(if={ p == 'like-write' }) いいねしたりいいね解除する。
li(if={ p == 'following-write' }) フォローしたりフォロー解除する。
li(if={ p == 'drive-read' }) ドライブを見る。
li(if={ p == 'drive-write' }) ドライブを操作する。
li(if={ p == 'notification-read' }) 通知を見る。
li(if={ p == 'notification-write' }) 通知を操作する。
<mk-form>
<header>
<h1><i>{ app.name }</i>があなたの<b>アカウント</b>に<b>アクセス</b>することを<b>許可</b>しますか?</h1><img src="{ app.icon_url + '?thumbnail&amp;size=64' }"/>
</header>
<div class="app">
<section>
<h2>{ app.name }</h2>
<p class="nid">{ app.name_id }</p>
<p class="description">{ app.description }</p>
</section>
<section>
<h2>このアプリは次の権限を要求しています:</h2>
<ul>
<virtual each="{ p in app.permission }">
<li if="{ p == 'account-read' }">アカウントの情報を見る。</li>
<li if="{ p == 'account-write' }">アカウントの情報を操作する。</li>
<li if="{ p == 'post-write' }">投稿する。</li>
<li if="{ p == 'like-write' }">いいねしたりいいね解除する。</li>
<li if="{ p == 'following-write' }">フォローしたりフォロー解除する。</li>
<li if="{ p == 'drive-read' }">ドライブを見る。</li>
<li if="{ p == 'drive-write' }">ドライブを操作する。</li>
<li if="{ p == 'notification-read' }">通知を見る。</li>
<li if="{ p == 'notification-write' }">通知を操作する。</li>
</virtual>
</ul>
</section>
</div>
<div class="action">
<button onclick="{ cancel }">キャンセル</button>
<button onclick="{ accept }">アクセスを許可</button>
</div>
<style type="stylus">
:scope
display block
div.action
button(onclick={ cancel }) キャンセル
button(onclick={ accept }) アクセスを許可
> header
> h1
margin 0
padding 32px 32px 20px 32px
font-size 24px
font-weight normal
color #777
style.
display block
i
color #77aeca
> header
> h1
margin 0
padding 32px 32px 20px 32px
font-size 24px
font-weight normal
color #777
&:before
content '「'
i
color #77aeca
&:after
content '」'
&:before
content '「'
b
color #666
> img
display block
z-index 1
width 84px
height 84px
margin 0 auto -38px auto
border solid 5px #fff
border-radius 100%
box-shadow 0 2px 2px rgba(0, 0, 0, 0.1)
> .app
padding 44px 16px 0 16px
color #555
background #eee
box-shadow 0 2px 2px rgba(0, 0, 0, 0.1) inset
&:after
content '」'
content ''
display block
clear both
b
color #666
> section
float left
width 50%
padding 8px
text-align left
> img
display block
z-index 1
width 84px
height 84px
margin 0 auto -38px auto
border solid 5px #fff
border-radius 100%
box-shadow 0 2px 2px rgba(0, 0, 0, 0.1)
> h2
margin 0
font-size 16px
color #777
> .app
padding 44px 16px 0 16px
color #555
background #eee
box-shadow 0 2px 2px rgba(0, 0, 0, 0.1) inset
> .action
padding 16px
&:after
content ''
display block
clear both
> button
margin 0 8px
> section
float left
width 50%
padding 8px
text-align left
@media (max-width 600px)
> header
> img
box-shadow none
> h2
margin 0
font-size 16px
color #777
> .app
box-shadow none
> .action
padding 16px
@media (max-width 500px)
> header
> h1
font-size 16px
> button
margin 0 8px
</style>
<script>
@mixin \api
@media (max-width 600px)
> header
> img
box-shadow none
@session = @opts.session
@app = @session.app
> .app
box-shadow none
@cancel = ~>
@api \auth/deny do
token: @session.token
.then ~>
@trigger \denied
@media (max-width 500px)
> header
> h1
font-size 16px
script.
@mixin \api
@session = @opts.session
@app = @session.app
@cancel = ~>
@api \auth/deny do
token: @session.token
.then ~>
@trigger \denied
@accept = ~>
@api \auth/accept do
token: @session.token
.then ~>
@trigger \accepted
@accept = ~>
@api \auth/accept do
token: @session.token
.then ~>
@trigger \accepted
</script>
</mk-form>

View File

@ -1,129 +1,136 @@
mk-index
main(if={ SIGNIN })
p.fetching(if={ fetching })
| 読み込み中
mk-ellipsis
mk-form@form(if={ state == null && !fetching }, session={ session })
div.denied(if={ state == 'denied' })
h1 アプリケーションの連携をキャンセルしました。
p このアプリがあなたのアカウントにアクセスすることはありません。
div.accepted(if={ state == 'accepted' })
h1 { session.app.is_authorized ? 'このアプリは既に連携済みです' : 'アプリケーションの連携を許可しました'}
p(if={ session.app.callback_url })
| アプリケーションに戻っています
mk-ellipsis
p(if={ !session.app.callback_url }) アプリケーションに戻って、やっていってください。
div.error(if={ state == 'fetch-session-error' })
p セッションが存在しません。
main.signin(if={ !SIGNIN })
h1 サインインしてください
mk-signin
footer
img(src='/_/resources/auth/logo.svg', alt='Misskey')
style.
display block
> main
width 100%
max-width 500px
margin 0 auto
text-align center
background #fff
box-shadow 0px 4px 16px rgba(0, 0, 0, 0.2)
> .fetching
margin 0
padding 32px
color #555
> div
padding 64px
> h1
margin 0 0 8px 0
padding 0
font-size 20px
font-weight normal
> p
margin 0
color #555
&.denied > h1
color #e65050
&.accepted > h1
color #50bbe6
&.signin
padding 32px 32px 16px 32px
> h1
margin 0 0 22px 0
padding 0
font-size 20px
font-weight normal
color #555
@media (max-width 600px)
max-width none
box-shadow none
@media (max-width 500px)
> div
> h1
font-size 16px
> footer
> img
<mk-index>
<main if="{ SIGNIN }">
<p class="fetching" if="{ fetching }">読み込み中
<mk-ellipsis></mk-ellipsis>
</p>
<mk-form ref="form" if="{ state == null &amp;&amp; !fetching }" session="{ session }"></mk-form>
<div class="denied" if="{ state == 'denied' }">
<h1>アプリケーションの連携をキャンセルしました。</h1>
<p>このアプリがあなたのアカウントにアクセスすることはありません。</p>
</div>
<div class="accepted" if="{ state == 'accepted' }">
<h1>{ session.app.is_authorized ? 'このアプリは既に連携済みです' : 'アプリケーションの連携を許可しました'}</h1>
<p if="{ session.app.callback_url }">アプリケーションに戻っています
<mk-ellipsis></mk-ellipsis>
</p>
<p if="{ !session.app.callback_url }">アプリケーションに戻って、やっていってください。</p>
</div>
<div class="error" if="{ state == 'fetch-session-error' }">
<p>セッションが存在しません。</p>
</div>
</main>
<main class="signin" if="{ !SIGNIN }">
<h1>サインインしてください</h1>
<mk-signin></mk-signin>
</main>
<footer><img src="/_/resources/auth/logo.svg" alt="Misskey"/></footer>
<style type="stylus">
:scope
display block
width 64px
height 64px
margin 0 auto
script.
@mixin \i
@mixin \api
> main
width 100%
max-width 500px
margin 0 auto
text-align center
background #fff
box-shadow 0px 4px 16px rgba(0, 0, 0, 0.2)
@state = null
@fetching = true
> .fetching
margin 0
padding 32px
color #555
@token = window.location.href.split \/ .pop!
> div
padding 64px
@on \mount ~>
if not @SIGNIN then return
> h1
margin 0 0 8px 0
padding 0
font-size 20px
font-weight normal
# Fetch session
@api \auth/session/show do
token: @token
.then (session) ~>
@session = session
@fetching = false
> p
margin 0
color #555
# 既に連携していた場合
if @session.app.is_authorized
@api \auth/accept do
token: @session.token
.then ~>
@accepted!
else
@update!
&.denied > h1
color #e65050
@refs.form.on \denied ~>
@state = \denied
&.accepted > h1
color #50bbe6
&.signin
padding 32px 32px 16px 32px
> h1
margin 0 0 22px 0
padding 0
font-size 20px
font-weight normal
color #555
@media (max-width 600px)
max-width none
box-shadow none
@media (max-width 500px)
> div
> h1
font-size 16px
> footer
> img
display block
width 64px
height 64px
margin 0 auto
</style>
<script>
@mixin \i
@mixin \api
@state = null
@fetching = true
@token = window.location.href.split \/ .pop!
@on \mount ~>
if not @SIGNIN then return
# Fetch session
@api \auth/session/show do
token: @token
.then (session) ~>
@session = session
@fetching = false
# 既に連携していた場合
if @session.app.is_authorized
@api \auth/accept do
token: @session.token
.then ~>
@accepted!
else
@update!
@refs.form.on \accepted @accepted
@refs.form.on \denied ~>
@state = \denied
@update!
.catch (error) ~>
@fetching = false
@state = \fetch-session-error
@refs.form.on \accepted @accepted
.catch (error) ~>
@fetching = false
@state = \fetch-session-error
@update!
@accepted = ~>
@state = \accepted
@update!
@accepted = ~>
@state = \accepted
@update!
if @session.app.callback_url
location.href = @session.app.callback_url + '?token=' + @session.token
if @session.app.callback_url
location.href = @session.app.callback_url + '?token=' + @session.token
</script>
</mk-index>

View File

@ -1,5 +1,11 @@
mk-copyright
span (c) syuilo 2014-2017
<mk-copyright><span>(c) syuilo 2014-2017</span>
<style type="stylus">
:scope
display block
style.
display block
</style>
</mk-copyright>

View File

@ -1,63 +1,64 @@
mk-core-error
//i: i.fa.fa-times-circle
img(src='/_/resources/error.jpg', alt='')
h1: mk-ripple-string サーバーに接続できません
p.text
| インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから
a(onclick={ retry }) 再度お試し
| ください。
p.thanks いつもMisskeyをご利用いただきありがとうございます。
<mk-core-error>
<!--i: i.fa.fa-times-circle--><img src="/_/resources/error.jpg" alt=""/>
<h1>
<mk-ripple-string>サーバーに接続できません</mk-ripple-string>
</h1>
<p class="text">インターネット回線に問題があるか、サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから<a onclick="{ retry }">再度お試し</a>ください。</p>
<p class="thanks">いつもMisskeyをご利用いただきありがとうございます。</p>
<style type="stylus">
:scope
position fixed
z-index 16385
top 0
left 0
width 100%
height 100%
text-align center
background #f8f8f8
style.
position fixed
z-index 16385
top 0
left 0
width 100%
height 100%
text-align center
background #f8f8f8
> i
display block
margin-top 64px
font-size 5em
color #6998a0
> i
display block
margin-top 64px
font-size 5em
color #6998a0
> img
display block
height 200px
margin 64px auto 0 auto
pointer-events none
-ms-user-select none
-moz-user-select none
-webkit-user-select none
user-select none
> img
display block
height 200px
margin 64px auto 0 auto
pointer-events none
-ms-user-select none
-moz-user-select none
-webkit-user-select none
user-select none
> h1
display block
margin 32px auto 16px auto
font-size 1.5em
color #555
> h1
display block
margin 32px auto 16px auto
font-size 1.5em
color #555
> .text
display block
margin 0 auto
max-width 600px
font-size 1em
color #666
> .text
display block
margin 0 auto
max-width 600px
font-size 1em
color #666
> .thanks
display block
margin 32px auto 0 auto
padding 32px 0 32px 0
max-width 600px
font-size 0.9em
font-style oblique
color #aaa
border-top solid 1px #eee
> .thanks
display block
margin 32px auto 0 auto
padding 32px 0 32px 0
max-width 600px
font-size 0.9em
font-style oblique
color #aaa
border-top solid 1px #eee
script.
@retry = ~>
@unmount!
@opts.retry!
</style>
<script>
@retry = ~>
@unmount!
@opts.retry!
</script>
</mk-core-error>

View File

@ -1,25 +1,29 @@
mk-ellipsis
span .
span .
span .
<mk-ellipsis><span>.</span><span>.</span><span>.</span>
<style type="stylus">
:scope
display inline
style.
display inline
> span
animation ellipsis 1.4s infinite ease-in-out both
> span
animation ellipsis 1.4s infinite ease-in-out both
&:nth-child(1)
animation-delay 0s
&:nth-child(1)
animation-delay 0s
&:nth-child(2)
animation-delay 0.16s
&:nth-child(2)
animation-delay 0.16s
&:nth-child(3)
animation-delay 0.32s
&:nth-child(3)
animation-delay 0.32s
@keyframes ellipsis
0%, 80%, 100%
opacity 1
40%
opacity 0
@keyframes ellipsis
0%, 80%, 100%
opacity 1
40%
opacity 0
</style>
</mk-ellipsis>

View File

@ -1,9 +1,11 @@
mk-file-type-icon
i.fa.fa-file-image-o(if={ kind == 'image' })
<mk-file-type-icon><i class="fa fa-file-image-o" if="{ kind == 'image' }"></i>
<style type="stylus">
:scope
display inline
style.
display inline
script.
@file = @opts.file
@kind = @file.type.split \/ .0
</style>
<script>
@file = @opts.file
@kind = @file.type.split \/ .0
</script>
</mk-file-type-icon>

View File

@ -1,37 +1,44 @@
mk-forkit
a(href='https://github.com/syuilo/misskey', target='_blank', title='View source on Github', aria-label='View source on Github')
svg(width='80', height='80', viewBox='0 0 250 250', aria-hidden)
path(d='M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z')
path.octo-arm(d='M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2', fill='currentColor')
path(d='M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z', fill='currentColor')
style.
display block
position absolute
top 0
right 0
> a
display block
> svg
<mk-forkit><a href="https://github.com/syuilo/misskey" target="_blank" title="View source on Github" aria-label="View source on Github">
<svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="aria-hidden">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
<path class="octo-arm" d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor"></path>
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor"></path>
</svg></a>
<style type="stylus">
:scope
display block
//fill #151513
//color #fff
fill $theme-color
color $theme-color-foreground
position absolute
top 0
right 0
.octo-arm
transform-origin 130px 106px
> a
display block
&:hover
.octo-arm
animation octocat-wave 560ms ease-in-out
> svg
display block
//fill #151513
//color #fff
fill $theme-color
color $theme-color-foreground
@keyframes octocat-wave
0%, 100%
transform rotate(0)
20%, 60%
transform rotate(-25deg)
40%, 80%
transform rotate(10deg)
.octo-arm
transform-origin 130px 106px
&:hover
.octo-arm
animation octocat-wave 560ms ease-in-out
@keyframes octocat-wave
0%, 100%
transform rotate(0)
20%, 60%
transform rotate(-25deg)
40%, 80%
transform rotate(10deg)
</style>
</mk-forkit>

View File

@ -1,22 +1,29 @@
mk-introduction
article
h1 Misskeyとは
<p><ruby>Misskey<rt>みすきー</rt></ruby>は、<a href="http://syuilo.com" target="_blank">syuilo</a>が2014年くらいから<a href="https://github.com/syuilo/misskey" target="_blank">オープンソースで</a>開発・運営を行っている、ミニブログベースのSNSです。</p>
<p>Twitter, Facebook, LINE, Google+ などを<del>パクって</del><i>参考にして</i>います。</p>
<p>無料で誰でも利用でき、広告は一切掲載していません。</p>
<p><a href={ CONFIG.urls.about } target="_blank">もっと知りたい方はこちら</a></p>
<mk-introduction>
<article>
<h1>Misskeyとは</h1><p><ruby>Misskey<rt>みすきー</rt></ruby>は、<a href="http://syuilo.com" target="_blank">syuilo</a>が2014年くらいから<a href="https://github.com/syuilo/misskey" target="_blank">オープンソースで</a>開発・運営を行っている、ミニブログベースのSNSです。</p>
<p>Twitter, Facebook, LINE, Google+ などを<del>パクって</del><i>参考にして</i>います。</p>
<p>無料で誰でも利用でき、広告は一切掲載していません。</p>
<p><a href="{ CONFIG.urls.about }" target="_blank">もっと知りたい方はこちら</a></p>
</article>
<style type="stylus">
:scope
display block
style.
display block
h1
margin 0
text-align center
font-size 1.2em
h1
margin 0
text-align center
font-size 1.2em
p
margin 16px 0
p
margin 16px 0
&:last-child
margin 0
text-align center
&:last-child
margin 0
text-align center
</style>
</mk-introduction>

View File

@ -1,15 +1,18 @@
mk-number
<mk-number>
<style type="stylus">
:scope
display inline
style.
display inline
</style>
<script>
@on \mount ~>
# バグ? https://github.com/riot/riot/issues/2103
#value = @opts.value
value = @opts.riot-value
max = @opts.max
script.
@on \mount ~>
# バグ? https://github.com/riot/riot/issues/2103
#value = @opts.value
value = @opts.riot-value
max = @opts.max
if max? then if value > max then value = max
if max? then if value > max then value = max
@root.innerHTML = value.to-locale-string!
@root.innerHTML = value.to-locale-string!
</script>
</mk-number>

View File

@ -1,7 +1,8 @@
mk-raw
<mk-raw>
<style type="stylus">
:scope
display inline
style.
display inline
script.
@root.innerHTML = @opts.content
</style>
<script>@root.innerHTML = @opts.content</script>
</mk-raw>

View File

@ -1,24 +1,26 @@
mk-ripple-string
<yield/>
<mk-ripple-string><yield/>
<style type="stylus">
:scope
display inline
style.
display inline
> span
animation ripple-string 5s infinite ease-in-out both
> span
animation ripple-string 5s infinite ease-in-out both
@keyframes ripple-string
0%, 50%, 100%
opacity 1
25%
opacity 0.5
@keyframes ripple-string
0%, 50%, 100%
opacity 1
25%
opacity 0.5
script.
@on \mount ~>
text = @root.innerHTML
@root.innerHTML = ''
(text.split '').for-each (c, i) ~>
ce = document.create-element \span
ce.innerHTML = c
ce.style.animation-delay = (i / 10) + 's'
@root.append-child ce
</style>
<script>
@on \mount ~>
text = @root.innerHTML
@root.innerHTML = ''
(text.split '').for-each (c, i) ~>
ce = document.create-element \span
ce.innerHTML = c
ce.style.animation-delay = (i / 10) + 's'
@root.append-child ce
</script>
</mk-ripple-string>

View File

@ -1,136 +1,131 @@
mk-signin
form(onsubmit={ onsubmit }, class={ signing: signing })
label.user-name
input@username(
type='text'
pattern='^[a-zA-Z0-9\-]+$'
placeholder='ユーザー名'
autofocus
required
oninput={ oninput })
i.fa.fa-at
label.password
input@password(
type='password'
placeholder='パスワード'
required)
i.fa.fa-lock
button(type='submit', disabled={ signing }) { signing ? 'やっています...' : 'サインイン' }
style.
display block
> form
display block
z-index 2
&.signing
&, *
cursor wait !important
label
<mk-signin>
<form class="{ signing: signing }" onsubmit="{ onsubmit }">
<label class="user-name">
<input ref="username" type="text" pattern="^[a-zA-Z0-9-]+$" placeholder="ユーザー名" autofocus="autofocus" required="required" oninput="{ oninput }"/><i class="fa fa-at"></i>
</label>
<label class="password">
<input ref="password" type="password" placeholder="パスワード" required="required"/><i class="fa fa-lock"></i>
</label>
<button type="submit" disabled="{ signing }">{ signing ? 'やっています...' : 'サインイン' }</button>
</form>
<style type="stylus">
:scope
display block
margin 12px 0
i
> form
display block
pointer-events none
position absolute
bottom 0
top 0
left 0
z-index 1
margin auto
padding 0 16px
height 1em
color #898786
z-index 2
input[type=text]
input[type=password]
user-select text
display inline-block
cursor auto
padding 0 0 0 38px
margin 0
width 100%
line-height 44px
font-size 1em
color rgba(0, 0, 0, 0.7)
background #fff
outline none
border solid 1px #eee
border-radius 4px
&.signing
&, *
cursor wait !important
&:hover
background rgba(255, 255, 255, 0.7)
border-color #ddd
label
display block
margin 12px 0
& + i
color #797776
i
display block
pointer-events none
position absolute
bottom 0
top 0
left 0
z-index 1
margin auto
padding 0 16px
height 1em
color #898786
&:focus
background #fff
border-color #ccc
input[type=text]
input[type=password]
user-select text
display inline-block
cursor auto
padding 0 0 0 38px
margin 0
width 100%
line-height 44px
font-size 1em
color rgba(0, 0, 0, 0.7)
background #fff
outline none
border solid 1px #eee
border-radius 4px
& + i
color #797776
&:hover
background rgba(255, 255, 255, 0.7)
border-color #ddd
[type=submit]
cursor pointer
padding 16px
margin -6px 0 0 0
width 100%
font-size 1.2em
color rgba(0, 0, 0, 0.5)
outline none
border none
border-radius 0
background transparent
transition all .5s ease
& + i
color #797776
&:hover
color $theme-color
transition all .2s ease
&:focus
background #fff
border-color #ccc
&:focus
color $theme-color
transition all .2s ease
& + i
color #797776
&:active
color darken($theme-color, 30%)
transition all .2s ease
[type=submit]
cursor pointer
padding 16px
margin -6px 0 0 0
width 100%
font-size 1.2em
color rgba(0, 0, 0, 0.5)
outline none
border none
border-radius 0
background transparent
transition all .5s ease
&:disabled
opacity 0.7
&:hover
color $theme-color
transition all .2s ease
script.
@mixin \api
&:focus
color $theme-color
transition all .2s ease
@user = null
@signing = false
&:active
color darken($theme-color, 30%)
transition all .2s ease
@oninput = ~>
@api \users/show do
username: @refs.username.value
.then (user) ~>
@user = user
@trigger \user user
&:disabled
opacity 0.7
</style>
<script>
@mixin \api
@user = null
@signing = false
@oninput = ~>
@api \users/show do
username: @refs.username.value
.then (user) ~>
@user = user
@trigger \user user
@update!
@onsubmit = (e) ~>
e.prevent-default!
@signing = true
@update!
@onsubmit = (e) ~>
e.prevent-default!
@api \signin do
username: @refs.username.value
password: @refs.password.value
.then ~>
location.reload!
.catch ~>
alert 'something happened'
@signing = false
@update!
@signing = true
@update!
@api \signin do
username: @refs.username.value
password: @refs.password.value
.then ~>
location.reload!
.catch ~>
alert 'something happened'
@signing = false
@update!
false
false
</script>
</mk-signin>

View File

@ -1,352 +1,293 @@
mk-signup
form(onsubmit={ onsubmit }, autocomplete='off')
label.username
p.caption
i.fa.fa-at
| ユーザー名
input@username(
type='text'
pattern='^[a-zA-Z0-9\-]{3,20}$'
placeholder='a~z、A~Z、0~9、-'
autocomplete='off'
required
onkeyup={ on-change-username })
p.profile-page-url-preview(if={ refs.username.value != '' && username-state != 'invalid-format' && username-state != 'min-range' && username-state != 'max-range' }) { CONFIG.url + '/' + refs.username.value }
p.info(if={ username-state == 'wait' }, style='color:#999')
i.fa.fa-fw.fa-spinner.fa-pulse
| 確認しています...
p.info(if={ username-state == 'ok' }, style='color:#3CB7B5')
i.fa.fa-fw.fa-check
| 利用できます
p.info(if={ username-state == 'unavailable' }, style='color:#FF1161')
i.fa.fa-fw.fa-exclamation-triangle
| 既に利用されています
p.info(if={ username-state == 'error' }, style='color:#FF1161')
i.fa.fa-fw.fa-exclamation-triangle
| 通信エラー
p.info(if={ username-state == 'invalid-format' }, style='color:#FF1161')
i.fa.fa-fw.fa-exclamation-triangle
| a~z、A~Z、0~9、-(ハイフン)が使えます
p.info(if={ username-state == 'min-range' }, style='color:#FF1161')
i.fa.fa-fw.fa-exclamation-triangle
| 3文字以上でお願いします
p.info(if={ username-state == 'max-range' }, style='color:#FF1161')
i.fa.fa-fw.fa-exclamation-triangle
| 20文字以内でお願いします
label.password
p.caption
i.fa.fa-lock
| パスワード
input@password(
type='password'
placeholder='8文字以上を推奨します'
autocomplete='off'
required
onkeyup={ on-change-password })
div.meter(if={ password-strength != '' }, data-strength={ password-strength })
div.value@password-metar
p.info(if={ password-strength == 'low' }, style='color:#FF1161')
i.fa.fa-fw.fa-exclamation-triangle
| 弱いパスワード
p.info(if={ password-strength == 'medium' }, style='color:#3CB7B5')
i.fa.fa-fw.fa-check
| まあまあのパスワード
p.info(if={ password-strength == 'high' }, style='color:#3CB7B5')
i.fa.fa-fw.fa-check
| 強いパスワード
label.retype-password
p.caption
i.fa.fa-lock
| パスワード(再入力)
input@password-retype(
type='password'
placeholder='確認のため再入力してください'
autocomplete='off'
required
onkeyup={ on-change-password-retype })
p.info(if={ password-retype-state == 'match' }, style='color:#3CB7B5')
i.fa.fa-fw.fa-check
| 確認されました
p.info(if={ password-retype-state == 'not-match' }, style='color:#FF1161')
i.fa.fa-fw.fa-exclamation-triangle
| 一致していません
label.recaptcha
p.caption
i.fa.fa-toggle-on(if={ recaptchaed })
i.fa.fa-toggle-off(if={ !recaptchaed })
| 認証
div.g-recaptcha(
data-callback='onRecaptchaed'
data-expired-callback='onRecaptchaExpired'
data-sitekey={ CONFIG.recaptcha.site-key })
label.agree-tou
input(
name='agree-tou',
type='checkbox',
autocomplete='off',
required)
p
a(href={ CONFIG.urls.about + '/tou' }, target='_blank') 利用規約
| に同意する
button(onclick={ onsubmit })
| アカウント作成
style.
display block
min-width 302px
overflow hidden
> form
label
<mk-signup>
<form onsubmit="{ onsubmit }" autocomplete="off">
<label class="username">
<p class="caption"><i class="fa fa-at"></i>ユーザー名</p>
<input ref="username" type="text" pattern="^[a-zA-Z0-9-]{3,20}$" placeholder="a~z、A~Z、0~9、-" autocomplete="off" required="required" onkeyup="{ onChangeUsername }"/>
<p class="profile-page-url-preview" if="{ refs.username.value != '' &amp;&amp; username-state != 'invalidFormat' &amp;&amp; username-state != 'minRange' &amp;&amp; username-state != 'maxRange' }">{ CONFIG.url + '/' + refs.username.value }</p>
<p class="info" if="{ usernameState == 'wait' }" style="color:#999"><i class="fa fa-fw fa-spinner fa-pulse"></i>確認しています...</p>
<p class="info" if="{ usernameState == 'ok' }" style="color:#3CB7B5"><i class="fa fa-fw fa-check"></i>利用できます</p>
<p class="info" if="{ usernameState == 'unavailable' }" style="color:#FF1161"><i class="fa fa-fw fa-exclamation-triangle"></i>既に利用されています</p>
<p class="info" if="{ usernameState == 'error' }" style="color:#FF1161"><i class="fa fa-fw fa-exclamation-triangle"></i>通信エラー</p>
<p class="info" if="{ usernameState == 'invalid-format' }" style="color:#FF1161"><i class="fa fa-fw fa-exclamation-triangle"></i>a~z、A~Z、0~9、-(ハイフン)が使えます</p>
<p class="info" if="{ usernameState == 'min-range' }" style="color:#FF1161"><i class="fa fa-fw fa-exclamation-triangle"></i>3文字以上でお願いします</p>
<p class="info" if="{ usernameState == 'max-range' }" style="color:#FF1161"><i class="fa fa-fw fa-exclamation-triangle"></i>20文字以内でお願いします</p>
</label>
<label class="password">
<p class="caption"><i class="fa fa-lock"></i>パスワード</p>
<input ref="password" type="password" placeholder="8文字以上を推奨します" autocomplete="off" required="required" onkeyup="{ onChangePassword }"/>
<div class="meter" if="{ passwordStrength != '' }" data-strength="{ passwordStrength }">
<div class="value" ref="passwordMetar"></div>
</div>
<p class="info" if="{ passwordStrength == 'low' }" style="color:#FF1161"><i class="fa fa-fw fa-exclamation-triangle"></i>弱いパスワード</p>
<p class="info" if="{ passwordStrength == 'medium' }" style="color:#3CB7B5"><i class="fa fa-fw fa-check"></i>まあまあのパスワード</p>
<p class="info" if="{ passwordStrength == 'high' }" style="color:#3CB7B5"><i class="fa fa-fw fa-check"></i>強いパスワード</p>
</label>
<label class="retype-password">
<p class="caption"><i class="fa fa-lock"></i>パスワード(再入力)</p>
<input ref="passwordRetype" type="password" placeholder="確認のため再入力してください" autocomplete="off" required="required" onkeyup="{ onChangePasswordRetype }"/>
<p class="info" if="{ passwordRetypeState == 'match' }" style="color:#3CB7B5"><i class="fa fa-fw fa-check"></i>確認されました</p>
<p class="info" if="{ passwordRetypeState == 'not-match' }" style="color:#FF1161"><i class="fa fa-fw fa-exclamation-triangle"></i>一致していません</p>
</label>
<label class="recaptcha">
<p class="caption"><i class="fa fa-toggle-on" if="{ recaptchaed }"></i><i class="fa fa-toggle-off" if="{ !recaptchaed }"></i>認証</p>
<div class="g-recaptcha" data-callback="onRecaptchaed" data-expired-callback="onRecaptchaExpired" data-sitekey="{ CONFIG.recaptcha.siteKey }"></div>
</label>
<label class="agree-tou">
<input name="agree-tou" type="checkbox" autocomplete="off" required="required"/>
<p><a href="{ CONFIG.urls.about + '/tou' }" target="_blank">利用規約</a>に同意する</p>
</label>
<button onclick="{ onsubmit }">アカウント作成</button>
</form>
<style type="stylus">
:scope
display block
margin 16px 0
min-width 302px
overflow hidden
> .caption
margin 0 0 4px 0
color #828888
font-size 0.95em
> form
> i
margin-right 0.25em
color #96adac
> .info
display block
margin 4px 0
font-size 0.8em
> i
margin-right 0.3em
&.username
.profile-page-url-preview
label
display block
margin 4px 8px 0 4px
font-size 0.8em
color #888
margin 16px 0
&:empty
display none
> .caption
margin 0 0 4px 0
color #828888
font-size 0.95em
&:not(:empty) + .info
margin-top 0
> i
margin-right 0.25em
color #96adac
&.password
.meter
display block
margin-top 8px
width 100%
height 8px
&[data-strength='']
display none
&[data-strength='low']
> .value
background #d73612
&[data-strength='medium']
> .value
background #d7ca12
&[data-strength='high']
> .value
background #61bb22
> .value
> .info
display block
width 0%
height 100%
background transparent
border-radius 4px
transition all 0.1s ease
margin 4px 0
font-size 0.8em
[type=text], [type=password]
user-select text
display inline-block
cursor auto
padding 0 12px
margin 0
width 100%
line-height 44px
font-size 1em
color #333 !important
background #fff !important
outline none
border solid 1px rgba(0, 0, 0, 0.1)
border-radius 4px
box-shadow 0 0 0 114514px #fff inset
transition all .3s ease
> i
margin-right 0.3em
&:hover
border-color rgba(0, 0, 0, 0.2)
transition all .1s ease
&.username
.profile-page-url-preview
display block
margin 4px 8px 0 4px
font-size 0.8em
color #888
&:focus
color $theme-color !important
border-color $theme-color
box-shadow 0 0 0 1024px #fff inset, 0 0 0 4px rgba($theme-color, 10%)
transition all 0s ease
&:empty
display none
&:disabled
opacity 0.5
&:not(:empty) + .info
margin-top 0
.agree-tou
padding 4px
border-radius 4px
&.password
.meter
display block
margin-top 8px
width 100%
height 8px
&:hover
background #f4f4f4
&[data-strength='']
display none
&:active
background #eee
&[data-strength='low']
> .value
background #d73612
&, *
cursor pointer
&[data-strength='medium']
> .value
background #d7ca12
p
display inline
color #555
&[data-strength='high']
> .value
background #61bb22
button
margin 0 0 32px 0
padding 16px
width 100%
font-size 1em
color #fff
background $theme-color
border-radius 3px
> .value
display block
width 0%
height 100%
background transparent
border-radius 4px
transition all 0.1s ease
&:hover
background lighten($theme-color, 5%)
[type=text], [type=password]
user-select text
display inline-block
cursor auto
padding 0 12px
margin 0
width 100%
line-height 44px
font-size 1em
color #333 !important
background #fff !important
outline none
border solid 1px rgba(0, 0, 0, 0.1)
border-radius 4px
box-shadow 0 0 0 114514px #fff inset
transition all .3s ease
&:active
background darken($theme-color, 5%)
&:hover
border-color rgba(0, 0, 0, 0.2)
transition all .1s ease
script.
@mixin \api
@mixin \get-password-strength
&:focus
color $theme-color !important
border-color $theme-color
box-shadow 0 0 0 1024px #fff inset, 0 0 0 4px rgba($theme-color, 10%)
transition all 0s ease
@username-state = null
@password-strength = ''
@password-retype-state = null
@recaptchaed = false
&:disabled
opacity 0.5
window.on-recaptchaed = ~>
@recaptchaed = true
@update!
.agree-tou
padding 4px
border-radius 4px
window.on-recaptcha-expired = ~>
&:hover
background #f4f4f4
&:active
background #eee
&, *
cursor pointer
p
display inline
color #555
button
margin 0 0 32px 0
padding 16px
width 100%
font-size 1em
color #fff
background $theme-color
border-radius 3px
&:hover
background lighten($theme-color, 5%)
&:active
background darken($theme-color, 5%)
</style>
<script>
@mixin \api
@mixin \get-password-strength
@username-state = null
@password-strength = ''
@password-retype-state = null
@recaptchaed = false
@update!
@on \mount ~>
head = (document.get-elements-by-tag-name \head).0
script = document.create-element \script
..set-attribute \src \https://www.google.com/recaptcha/api.js
head.append-child script
@on-change-username = ~>
username = @refs.username.value
if username == ''
@username-state = null
@update!
return
err = switch
| not username.match /^[a-zA-Z0-9\-]+$/ => \invalid-format
| username.length < 3chars => \min-range
| username.length > 20chars => \max-range
| _ => null
if err?
@username-state = err
@update!
else
@username-state = \wait
window.on-recaptchaed = ~>
@recaptchaed = true
@update!
@api \username/available do
username: username
.then (result) ~>
if result.available
@username-state = \ok
else
@username-state = \unavailable
window.on-recaptcha-expired = ~>
@recaptchaed = false
@update!
@on \mount ~>
head = (document.get-elements-by-tag-name \head).0
script = document.create-element \script
..set-attribute \src \https://www.google.com/recaptcha/api.js
head.append-child script
@on-change-username = ~>
username = @refs.username.value
if username == ''
@username-state = null
@update!
.catch (err) ~>
@username-state = \error
return
err = switch
| not username.match /^[a-zA-Z0-9\-]+$/ => \invalid-format
| username.length < 3chars => \min-range
| username.length > 20chars => \max-range
| _ => null
if err?
@username-state = err
@update!
else
@username-state = \wait
@update!
@on-change-password = ~>
password = @refs.password.value
@api \username/available do
username: username
.then (result) ~>
if result.available
@username-state = \ok
else
@username-state = \unavailable
@update!
.catch (err) ~>
@username-state = \error
@update!
if password == ''
@password-strength = ''
return
@on-change-password = ~>
password = @refs.password.value
strength = @get-password-strength password
if password == ''
@password-strength = ''
return
if strength > 0.3
@password-strength = \medium
if strength > 0.7
@password-strength = \high
else
@password-strength = \low
strength = @get-password-strength password
@update!
if strength > 0.3
@password-strength = \medium
if strength > 0.7
@password-strength = \high
else
@password-strength = \low
@refs.password-metar.style.width = (strength * 100) + \%
@update!
@on-change-password-retype = ~>
password = @refs.password.value
retyped-password = @refs.password-retype.value
@refs.password-metar.style.width = (strength * 100) + \%
if retyped-password == ''
@password-retype-state = null
return
@on-change-password-retype = ~>
password = @refs.password.value
retyped-password = @refs.password-retype.value
if password == retyped-password
@password-retype-state = \match
else
@password-retype-state = \not-match
if retyped-password == ''
@password-retype-state = null
return
@onsubmit = (e) ~>
e.prevent-default!
if password == retyped-password
@password-retype-state = \match
else
@password-retype-state = \not-match
username = @refs.username.value
password = @refs.password.value
@onsubmit = (e) ~>
e.prevent-default!
locker = document.body.append-child document.create-element \mk-locker
username = @refs.username.value
password = @refs.password.value
@api \signup do
username: username
password: password
'g-recaptcha-response': grecaptcha.get-response!
.then ~>
@api \signin do
locker = document.body.append-child document.create-element \mk-locker
@api \signup do
username: username
password: password
'g-recaptcha-response': grecaptcha.get-response!
.then ~>
location.href = CONFIG.url
.catch ~>
alert '何らかの原因によりアカウントの作成に失敗しました。再度お試しください。'
@api \signin do
username: username
password: password
.then ~>
location.href = CONFIG.url
.catch ~>
alert '何らかの原因によりアカウントの作成に失敗しました。再度お試しください。'
grecaptcha.reset!
@recaptchaed = false
grecaptcha.reset!
@recaptchaed = false
locker.parent-node.remove-child locker
locker.parent-node.remove-child locker
false
false
</script>
</mk-signup>

View File

@ -1,24 +1,27 @@
mk-special-message
p(if={ m == 1 && d == 1 }) Happy New Year!
p(if={ m == 12 && d == 25 }) Merry Christmas!
<mk-special-message>
<p if="{ m == 1 &amp;&amp; d == 1 }">Happy New Year! </p>
<p if="{ m == 12 &amp;&amp; d == 25 }">Merry Christmas!</p>
<style type="stylus">
:scope
display block
style.
display block
&:empty
display none
&:empty
display none
> p
margin 0
padding 4px
text-align center
font-size 14px
font-weight bold
text-transform uppercase
color #fff
background #ff1036
> p
margin 0
padding 4px
text-align center
font-size 14px
font-weight bold
text-transform uppercase
color #fff
background #ff1036
script.
now = new Date!
@d = now.get-date!
@m = now.get-month! + 1
</style>
<script>
now = new Date!
@d = now.get-date!
@m = now.get-month! + 1
</script>
</mk-special-message>

View File

@ -1,43 +1,41 @@
mk-time
time(datetime={ opts.time })
span(if={ mode == 'relative' }) { relative }
span(if={ mode == 'absolute' }) { absolute }
span(if={ mode == 'detail' }) { absolute } ({ relative })
<mk-time>
<time datetime="{ opts.time }"><span if="{ mode == 'relative' }">{ relative }</span><span if="{ mode == 'absolute' }">{ absolute }</span><span if="{ mode == 'detail' }">{ absolute } ({ relative })</span></time>
<script>
@time = new Date @opts.time
@mode = @opts.mode || \relative
@tickid = null
script.
@time = new Date @opts.time
@mode = @opts.mode || \relative
@tickid = null
@absolute =
@time.get-full-year! + \年 +
@time.get-month! + 1 + \月 +
@time.get-date! + \日 +
' ' +
@time.get-hours! + \時 +
@time.get-minutes! + \分
@absolute =
@time.get-full-year! + \年 +
@time.get-month! + 1 + \月 +
@time.get-date! + \日 +
' ' +
@time.get-hours! + \時 +
@time.get-minutes! + \分
@on \mount ~>
if @mode == \relative or @mode == \detail
@tick!
@tickid = set-interval @tick, 1000ms
@on \mount ~>
if @mode == \relative or @mode == \detail
@tick!
@tickid = set-interval @tick, 1000ms
@on \unmount ~>
if @mode == \relative or @mode == \detail
clear-interval @tickid
@on \unmount ~>
if @mode == \relative or @mode == \detail
clear-interval @tickid
@tick = ~>
now = new Date!
ago = (now - @time) / 1000ms
@relative = switch
| ago >= 31536000s => ~~(ago / 31536000s) + '年前'
| ago >= 2592000s => ~~(ago / 2592000s) + 'ヶ月前'
| ago >= 604800s => ~~(ago / 604800s) + '週間前'
| ago >= 86400s => ~~(ago / 86400s) + '日前'
| ago >= 3600s => ~~(ago / 3600s) + '時間前'
| ago >= 60s => ~~(ago / 60s) + '分前'
| ago >= 10s => ~~(ago % 60s) + '秒前'
| ago >= 0s => 'たった今'
| ago < 0s => '未来'
| _ => 'なぞのじかん'
@update!
@tick = ~>
now = new Date!
ago = (now - @time) / 1000ms
@relative = switch
| ago >= 31536000s => ~~(ago / 31536000s) + '年前'
| ago >= 2592000s => ~~(ago / 2592000s) + 'ヶ月前'
| ago >= 604800s => ~~(ago / 604800s) + '週間前'
| ago >= 86400s => ~~(ago / 86400s) + '日前'
| ago >= 3600s => ~~(ago / 3600s) + '時間前'
| ago >= 60s => ~~(ago / 60s) + '分前'
| ago >= 10s => ~~(ago % 60s) + '秒前'
| ago >= 0s => 'たった今'
| ago < 0s => '未来'
| _ => 'なぞのじかん'
@update!
</script>
</mk-time>

View File

@ -1,201 +1,195 @@
mk-uploader
ol(if={ uploads.length > 0 })
li(each={ uploads })
div.img(style='background-image: url({ img })')
p.name
i.fa.fa-spinner.fa-pulse
| { name }
p.status
span.initing(if={ progress == undefined })
| 待機中
mk-ellipsis
span.kb(if={ progress != undefined })
| { String(Math.floor(progress.value / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }
i KB
= ' / '
| { String(Math.floor(progress.max / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }
i KB
span.percentage(if={ progress != undefined }) { Math.floor((progress.value / progress.max) * 100) }
progress(if={ progress != undefined && progress.value != progress.max }, value={ progress.value }, max={ progress.max })
div.progress.initing(if={ progress == undefined })
div.progress.waiting(if={ progress != undefined && progress.value == progress.max })
style.
display block
overflow auto
&:empty
display none
> ol
display block
margin 0
padding 0
list-style none
> li
<mk-uploader>
<ol if="{ uploads.length &gt; 0 }">
<li each="{ uploads }">
<div class="img" style="background-image: url({ img })"></div>
<p class="name"><i class="fa fa-spinner fa-pulse"></i>{ name }</p>
<p class="status"><span class="initing" if="{ progress == undefined }">待機中
<mk-ellipsis></mk-ellipsis></span><span class="kb" if="{ progress != undefined }">{ String(Math.floor(progress.value / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }<i>KB</i> / { String(Math.floor(progress.max / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }<i>KB</i></span><span class="percentage" if="{ progress != undefined }">{ Math.floor((progress.value / progress.max) * 100) }</span></p>
<progress if="{ progress != undefined &amp;&amp; progress.value != progress.max }" value="{ progress.value }" max="{ progress.max }"></progress>
<div class="progress initing" if="{ progress == undefined }"></div>
<div class="progress waiting" if="{ progress != undefined &amp;&amp; progress.value == progress.max }"></div>
</li>
</ol>
<style type="stylus">
:scope
display block
margin 8px 0 0 0
padding 0
height 36px
box-shadow 0 -1px 0 rgba($theme-color, 0.1)
border-top solid 8px transparent
overflow auto
&:first-child
margin 0
box-shadow none
border-top none
&:empty
display none
> .img
> ol
display block
position absolute
top 0
left 0
width 36px
height 36px
background-size cover
background-position center center
> .name
display block
position absolute
top 0
left 44px
margin 0
padding 0
max-width 256px
font-size 0.8em
color rgba($theme-color, 0.7)
white-space nowrap
text-overflow ellipsis
overflow hidden
list-style none
> i
margin-right 4px
> li
display block
margin 8px 0 0 0
padding 0
height 36px
box-shadow 0 -1px 0 rgba($theme-color, 0.1)
border-top solid 8px transparent
> .status
display block
position absolute
top 0
right 0
margin 0
padding 0
font-size 0.8em
&:first-child
margin 0
box-shadow none
border-top none
> .initing
color rgba($theme-color, 0.5)
> .img
display block
position absolute
top 0
left 0
width 36px
height 36px
background-size cover
background-position center center
> .kb
color rgba($theme-color, 0.5)
> .name
display block
position absolute
top 0
left 44px
margin 0
padding 0
max-width 256px
font-size 0.8em
color rgba($theme-color, 0.7)
white-space nowrap
text-overflow ellipsis
overflow hidden
> .percentage
display inline-block
width 48px
text-align right
> i
margin-right 4px
color rgba($theme-color, 0.7)
> .status
display block
position absolute
top 0
right 0
margin 0
padding 0
font-size 0.8em
&:after
content '%'
> .initing
color rgba($theme-color, 0.5)
> progress
display block
position absolute
bottom 0
right 0
margin 0
width calc(100% - 44px)
height 8px
background transparent
border none
border-radius 4px
overflow hidden
> .kb
color rgba($theme-color, 0.5)
&::-webkit-progress-value
background $theme-color
> .percentage
display inline-block
width 48px
text-align right
&::-webkit-progress-bar
background rgba($theme-color, 0.1)
color rgba($theme-color, 0.7)
> .progress
display block
position absolute
bottom 0
right 0
margin 0
width calc(100% - 44px)
height 8px
border none
border-radius 4px
background linear-gradient(
45deg,
lighten($theme-color, 30%) 25%,
$theme-color 25%,
$theme-color 50%,
lighten($theme-color, 30%) 50%,
lighten($theme-color, 30%) 75%,
$theme-color 75%,
$theme-color
)
background-size 32px 32px
animation bg 1.5s linear infinite
&:after
content '%'
&.initing
opacity 0.3
> progress
display block
position absolute
bottom 0
right 0
margin 0
width calc(100% - 44px)
height 8px
background transparent
border none
border-radius 4px
overflow hidden
@keyframes bg
from {background-position: 0 0;}
to {background-position: -64px 32px;}
&::-webkit-progress-value
background $theme-color
script.
@mixin \i
&::-webkit-progress-bar
background rgba($theme-color, 0.1)
@uploads = []
> .progress
display block
position absolute
bottom 0
right 0
margin 0
width calc(100% - 44px)
height 8px
border none
border-radius 4px
background linear-gradient(
45deg,
lighten($theme-color, 30%) 25%,
$theme-color 25%,
$theme-color 50%,
lighten($theme-color, 30%) 50%,
lighten($theme-color, 30%) 75%,
$theme-color 75%,
$theme-color
)
background-size 32px 32px
animation bg 1.5s linear infinite
&.initing
opacity 0.3
@upload = (file, folder) ~>
id = Math.random!
@keyframes bg
from {background-position: 0 0;}
to {background-position: -64px 32px;}
ctx =
id: id
name: file.name || \untitled
progress: undefined
</style>
<script>
@mixin \i
@uploads.push ctx
@trigger \change-uploads @uploads
@update!
@uploads = []
reader = new FileReader!
reader.onload = (e) ~>
ctx.img = e.target.result
@update!
reader.read-as-data-URL file
@upload = (file, folder) ~>
id = Math.random!
data = new FormData!
data.append \i @I.token
data.append \file file
ctx =
id: id
name: file.name || \untitled
progress: undefined
if folder?
data.append \folder_id folder
xhr = new XMLHttpRequest!
xhr.open \POST CONFIG.api.url + '/drive/files/create' true
xhr.onload = (e) ~>
drive-file = JSON.parse e.target.response
@trigger \uploaded drive-file
@uploads = @uploads.filter (x) -> x.id != id
@uploads.push ctx
@trigger \change-uploads @uploads
@update!
xhr.upload.onprogress = (e) ~>
if e.length-computable
if ctx.progress == undefined
ctx.progress = {}
ctx.progress.max = e.total
ctx.progress.value = e.loaded
reader = new FileReader!
reader.onload = (e) ~>
ctx.img = e.target.result
@update!
reader.read-as-data-URL file
data = new FormData!
data.append \i @I.token
data.append \file file
if folder?
data.append \folder_id folder
xhr = new XMLHttpRequest!
xhr.open \POST CONFIG.api.url + '/drive/files/create' true
xhr.onload = (e) ~>
drive-file = JSON.parse e.target.response
@trigger \uploaded drive-file
@uploads = @uploads.filter (x) -> x.id != id
@trigger \change-uploads @uploads
@update!
xhr.send data
xhr.upload.onprogress = (e) ~>
if e.length-computable
if ctx.progress == undefined
ctx.progress = {}
ctx.progress.max = e.total
ctx.progress.value = e.loaded
@update!
xhr.send data
</script>
</mk-uploader>

View File

@ -1,105 +1,110 @@
mk-url-preview
a(href={ url }, target='_blank', title={ url }, if={ !loading })
div.thumbnail(if={ thumbnail }, style={ 'background-image: url(' + thumbnail + ')' })
article
header: h1 { title }
p { description }
footer
img.icon(if={ icon }, src={ icon })
p { sitename }
<mk-url-preview><a href="{ url }" target="_blank" title="{ url }" if="{ !loading }">
<div class="thumbnail" if="{ thumbnail }" style="{ 'background-image: url(' + thumbnail + ')' }"></div>
<article>
<header>
<h1>{ title }</h1>
</header>
<p>{ description }</p>
<footer><img class="icon" if="{ icon }" src="{ icon }"/>
<p>{ sitename }</p>
</footer>
</article></a>
<style type="stylus">
:scope
display block
font-size 16px
style.
display block
font-size 16px
> a
display block
border solid 1px #eee
border-radius 4px
overflow hidden
> a
display block
border solid 1px #eee
border-radius 4px
overflow hidden
&:hover
text-decoration none
border-color #ddd
&:hover
text-decoration none
border-color #ddd
> article > header > h1
text-decoration underline
> article > header > h1
text-decoration underline
> .thumbnail
position absolute
width 100px
height 100%
background-position center
background-size cover
> .thumbnail
position absolute
width 100px
height 100%
background-position center
background-size cover
& + article
left 100px
width calc(100% - 100px)
& + article
left 100px
width calc(100% - 100px)
> article
padding 16px
> article
padding 16px
> header
margin-bottom 8px
> header
margin-bottom 8px
> h1
margin 0
font-size 1em
color #555
> h1
margin 0
font-size 1em
color #555
> p
margin 0
color #777
font-size 0.8em
> p
margin 0
color #777
font-size 0.8em
> footer
margin-top 8px
> footer
margin-top 8px
> img
display inline-block
width 16px
heigth 16px
margin-right 4px
vertical-align bottom
> img
display inline-block
width 16px
heigth 16px
margin-right 4px
vertical-align bottom
> p
display inline-block
margin 0
color #666
font-size 0.8em
line-height 16px
> p
display inline-block
margin 0
color #666
font-size 0.8em
line-height 16px
@media (max-width 500px)
font-size 8px
@media (max-width 500px)
font-size 8px
> a
border none
> a
border none
> .thumbnail
width 70px
> .thumbnail
width 70px
& + article
left 70px
width calc(100% - 70px)
& + article
left 70px
width calc(100% - 70px)
> article
padding 8px
> article
padding 8px
</style>
<script>
@mixin \api
script.
@mixin \api
@url = @opts.url
@loading = true
@url = @opts.url
@loading = true
@on \mount ~>
fetch CONFIG.url + '/api:url?url=' + @url
.then (res) ~>
info <~ res.json!.then
@title = info.title
@description = info.description
@thumbnail = info.thumbnail
@icon = info.icon
@sitename = info.sitename
@on \mount ~>
fetch CONFIG.url + '/api:url?url=' + @url
.then (res) ~>
info <~ res.json!.then
@title = info.title
@description = info.description
@thumbnail = info.thumbnail
@icon = info.icon
@sitename = info.sitename
@loading = false
@update!
@loading = false
@update!
</script>
</mk-url-preview>

View File

@ -1,50 +1,46 @@
mk-url
a(href={ url }, target={ opts.target })
span.schema { schema }//
span.hostname { hostname }
span.port(if={ port != '' }) :{ port }
span.pathname(if={ pathname != '' }) { pathname }
span.query { query }
span.hash { hash }
<mk-url><a href="{ url }" target="{ opts.target }"><span class="schema">{ schema }//</span><span class="hostname">{ hostname }</span><span class="port" if="{ port != '' }">:{ port }</span><span class="pathname" if="{ pathname != '' }">{ pathname }</span><span class="query">{ query }</span><span class="hash">{ hash }</span></a>
<style type="stylus">
:scope
> a
&:after
content "\f14c"
display inline-block
padding-left 2px
font-family FontAwesome
font-size .9em
font-weight 400
font-style normal
style.
> a
&:after
content "\f14c"
display inline-block
padding-left 2px
font-family FontAwesome
font-size .9em
font-weight 400
font-style normal
> .schema
opacity 0.5
> .schema
opacity 0.5
> .hostname
font-weight bold
> .hostname
font-weight bold
> .pathname
opacity 0.8
> .pathname
opacity 0.8
> .query
opacity 0.5
> .query
opacity 0.5
> .hash
font-style italic
> .hash
font-style italic
</style>
<script>
@url = @opts.href
script.
@url = @opts.href
@on \before-mount ~>
parser = document.create-element \a
parser.href = @url
@on \before-mount ~>
parser = document.create-element \a
parser.href = @url
@schema = parser.protocol
@hostname = parser.hostname
@port = parser.port
@pathname = parser.pathname
@query = parser.search
@hash = parser.hash
@schema = parser.protocol
@hostname = parser.hostname
@port = parser.port
@pathname = parser.pathname
@query = parser.search
@hash = parser.hash
@update!
@update!
</script>
</mk-url>

View File

@ -1,102 +1,105 @@
mk-analog-clock
canvas@canvas(width='256', height='256')
<mk-analog-clock>
<canvas ref="canvas" width="256" height="256"></canvas>
<style type="stylus">
:scope
> canvas
display block
width 256px
height 256px
style.
> canvas
display block
width 256px
height 256px
</style>
<script>
@on \mount ~>
@draw!
@clock = set-interval @draw, 1000ms
script.
@on \mount ~>
@draw!
@clock = set-interval @draw, 1000ms
@on \unmount ~>
clear-interval @clock
@on \unmount ~>
clear-interval @clock
@draw = ~>
now = new Date!
s = now.get-seconds!
m = now.get-minutes!
h = now.get-hours!
@draw = ~>
now = new Date!
s = now.get-seconds!
m = now.get-minutes!
h = now.get-hours!
vec2 = (x, y) ->
@x = x
@y = y
vec2 = (x, y) ->
@x = x
@y = y
ctx = @refs.canvas.get-context \2d
canv-w = @refs.canvas.width
canv-h = @refs.canvas.height
ctx.clear-rect 0, 0, canv-w, canv-h
ctx = @refs.canvas.get-context \2d
canv-w = @refs.canvas.width
canv-h = @refs.canvas.height
ctx.clear-rect 0, 0, canv-w, canv-h
# 背景
center = (Math.min (canv-w / 2), (canv-h / 2))
line-start = center * 0.90
line-end-short = center * 0.87
line-end-long = center * 0.84
for i from 0 to 59 by 1
angle = Math.PI * i / 30
uv = new vec2 (Math.sin angle), (-Math.cos angle)
ctx.begin-path!
ctx.line-width = 1
ctx.move-to do
(canv-w / 2) + uv.x * line-start
(canv-h / 2) + uv.y * line-start
if i % 5 == 0
ctx.stroke-style = 'rgba(255, 255, 255, 0.2)'
ctx.line-to do
(canv-w / 2) + uv.x * line-end-long
(canv-h / 2) + uv.y * line-end-long
else
ctx.stroke-style = 'rgba(255, 255, 255, 0.1)'
ctx.line-to do
(canv-w / 2) + uv.x * line-end-short
(canv-h / 2) + uv.y * line-end-short
ctx.stroke!
# 背景
center = (Math.min (canv-w / 2), (canv-h / 2))
line-start = center * 0.90
line-end-short = center * 0.87
line-end-long = center * 0.84
for i from 0 to 59 by 1
angle = Math.PI * i / 30
# 分
angle = Math.PI * (m + s / 60) / 30
length = (Math.min canv-w, canv-h) / 2.6
uv = new vec2 (Math.sin angle), (-Math.cos angle)
ctx.begin-path!
ctx.line-width = 1
ctx.stroke-style = \#ffffff
ctx.line-width = 2
ctx.move-to do
(canv-w / 2) + uv.x * line-start
(canv-h / 2) + uv.y * line-start
if i % 5 == 0
ctx.stroke-style = 'rgba(255, 255, 255, 0.2)'
ctx.line-to do
(canv-w / 2) + uv.x * line-end-long
(canv-h / 2) + uv.y * line-end-long
else
ctx.stroke-style = 'rgba(255, 255, 255, 0.1)'
ctx.line-to do
(canv-w / 2) + uv.x * line-end-short
(canv-h / 2) + uv.y * line-end-short
(canv-w / 2) - uv.x * length / 5
(canv-h / 2) - uv.y * length / 5
ctx.line-to do
(canv-w / 2) + uv.x * length
(canv-h / 2) + uv.y * length
ctx.stroke!
# 分
angle = Math.PI * (m + s / 60) / 30
length = (Math.min canv-w, canv-h) / 2.6
uv = new vec2 (Math.sin angle), (-Math.cos angle)
ctx.begin-path!
ctx.stroke-style = \#ffffff
ctx.line-width = 2
ctx.move-to do
(canv-w / 2) - uv.x * length / 5
(canv-h / 2) - uv.y * length / 5
ctx.line-to do
(canv-w / 2) + uv.x * length
(canv-h / 2) + uv.y * length
ctx.stroke!
# 時
angle = Math.PI * (h % 12 + m / 60) / 6
length = (Math.min canv-w, canv-h) / 4
uv = new vec2 (Math.sin angle), (-Math.cos angle)
ctx.begin-path!
#ctx.stroke-style = \#ffffff
ctx.stroke-style = CONFIG.theme-color
ctx.line-width = 2
ctx.move-to do
(canv-w / 2) - uv.x * length / 5
(canv-h / 2) - uv.y * length / 5
ctx.line-to do
(canv-w / 2) + uv.x * length
(canv-h / 2) + uv.y * length
ctx.stroke!
# 時
angle = Math.PI * (h % 12 + m / 60) / 6
length = (Math.min canv-w, canv-h) / 4
uv = new vec2 (Math.sin angle), (-Math.cos angle)
ctx.begin-path!
#ctx.stroke-style = \#ffffff
ctx.stroke-style = CONFIG.theme-color
ctx.line-width = 2
ctx.move-to do
(canv-w / 2) - uv.x * length / 5
(canv-h / 2) - uv.y * length / 5
ctx.line-to do
(canv-w / 2) + uv.x * length
(canv-h / 2) + uv.y * length
ctx.stroke!
# 秒
angle = Math.PI * s / 30
length = (Math.min canv-w, canv-h) / 2.6
uv = new vec2 (Math.sin angle), (-Math.cos angle)
ctx.begin-path!
ctx.stroke-style = 'rgba(255, 255, 255, 0.5)'
ctx.line-width = 1
ctx.move-to do
(canv-w / 2) - uv.x * length / 5
(canv-h / 2) - uv.y * length / 5
ctx.line-to do
(canv-w / 2) + uv.x * length
(canv-h / 2) + uv.y * length
ctx.stroke!
# 秒
angle = Math.PI * s / 30
length = (Math.min canv-w, canv-h) / 2.6
uv = new vec2 (Math.sin angle), (-Math.cos angle)
ctx.begin-path!
ctx.stroke-style = 'rgba(255, 255, 255, 0.5)'
ctx.line-width = 1
ctx.move-to do
(canv-w / 2) - uv.x * length / 5
(canv-h / 2) - uv.y * length / 5
ctx.line-to do
(canv-w / 2) + uv.x * length
(canv-h / 2) + uv.y * length
ctx.stroke!
</script>
</mk-analog-clock>

View File

@ -1,182 +1,183 @@
mk-autocomplete-suggestion
ol.users@users(if={ users.length > 0 })
li(each={ users }, onclick={ parent.on-click }, onkeydown={ parent.on-keydown }, tabindex='-1')
img.avatar(src={ avatar_url + '?thumbnail&size=32' }, alt='')
span.name { name }
span.username @{ username }
style.
display block
position absolute
z-index 65535
margin-top calc(1em + 8px)
overflow hidden
background #fff
border solid 1px rgba(0, 0, 0, 0.1)
border-radius 4px
> .users
display block
margin 0
padding 4px 0
max-height 190px
max-width 500px
overflow auto
list-style none
> li
<mk-autocomplete-suggestion>
<ol class="users" ref="users" if="{ users.length &gt; 0 }">
<li each="{ users }" onclick="{ parent.onClick }" onkeydown="{ parent.onKeydown }" tabindex="-1"><img class="avatar" src="{ avatar_url + '?thumbnail&amp;size=32' }" alt=""/><span class="name">{ name }</span><span class="username">@{ username }</span></li>
</ol>
<style type="stylus">
:scope
display block
padding 4px 12px
white-space nowrap
position absolute
z-index 65535
margin-top calc(1em + 8px)
overflow hidden
font-size 0.9em
color rgba(0, 0, 0, 0.8)
cursor default
background #fff
border solid 1px rgba(0, 0, 0, 0.1)
border-radius 4px
&, *
user-select none
> .users
display block
margin 0
padding 4px 0
max-height 190px
max-width 500px
overflow auto
list-style none
&:hover
&[data-selected='true']
color #fff
background $theme-color
> li
display block
padding 4px 12px
white-space nowrap
overflow hidden
font-size 0.9em
color rgba(0, 0, 0, 0.8)
cursor default
.name
color #fff
&, *
user-select none
.username
color #fff
&:hover
&[data-selected='true']
color #fff
background $theme-color
&:active
color #fff
background darken($theme-color, 10%)
.name
color #fff
.name
color #fff
.username
color #fff
.username
color #fff
&:active
color #fff
background darken($theme-color, 10%)
.avatar
vertical-align middle
min-width 28px
min-height 28px
max-width 28px
max-height 28px
margin 0 8px 0 0
border-radius 100%
.name
color #fff
.name
margin 0 8px 0 0
/*font-weight bold*/
font-weight normal
color rgba(0, 0, 0, 0.8)
.username
color #fff
.username
font-weight normal
color rgba(0, 0, 0, 0.3)
.avatar
vertical-align middle
min-width 28px
min-height 28px
max-width 28px
max-height 28px
margin 0 8px 0 0
border-radius 100%
script.
@mixin \api
.name
margin 0 8px 0 0
/*font-weight bold*/
font-weight normal
color rgba(0, 0, 0, 0.8)
@q = @opts.q
@textarea = @opts.textarea
@loading = true
@users = []
@select = -1
.username
font-weight normal
color rgba(0, 0, 0, 0.3)
@on \mount ~>
@textarea.add-event-listener \keydown @on-keydown
</style>
<script>
@mixin \api
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.add-event-listener \mousedown @mousedown
@q = @opts.q
@textarea = @opts.textarea
@loading = true
@users = []
@select = -1
@api \users/search_by_username do
query: @q
limit: 30users
.then (users) ~>
@users = users
@loading = false
@update!
.catch (err) ~>
console.error err
@on \mount ~>
@textarea.add-event-listener \keydown @on-keydown
@on \unmount ~>
@textarea.remove-event-listener \keydown @on-keydown
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.add-event-listener \mousedown @mousedown
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.remove-event-listener \mousedown @mousedown
@api \users/search_by_username do
query: @q
limit: 30users
.then (users) ~>
@users = users
@loading = false
@update!
.catch (err) ~>
console.error err
@mousedown = (e) ~>
if (!contains @root, e.target) and (@root != e.target)
@close!
@on \unmount ~>
@textarea.remove-event-listener \keydown @on-keydown
@on-click = (e) ~>
@complete e.item
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.remove-event-listener \mousedown @mousedown
@on-keydown = (e) ~>
key = e.which
switch (key)
| 10, 13 => # Key[ENTER]
if @select != -1
e.prevent-default!
e.stop-propagation!
@complete @users[@select]
else
@close!
| 27 => # Key[ESC]
e.prevent-default!
e.stop-propagation!
@close!
| 38 => # Key[↑]
if @select != -1
e.prevent-default!
e.stop-propagation!
@select-prev!
else
@close!
| 9, 40 => # Key[TAB] or Key[↓]
e.prevent-default!
e.stop-propagation!
@select-next!
| _ =>
@mousedown = (e) ~>
if (!contains @root, e.target) and (@root != e.target)
@close!
@select-next = ~>
@select++
@on-click = (e) ~>
@complete e.item
if @select >= @users.length
@select = 0
@on-keydown = (e) ~>
key = e.which
switch (key)
| 10, 13 => # Key[ENTER]
if @select != -1
e.prevent-default!
e.stop-propagation!
@complete @users[@select]
else
@close!
| 27 => # Key[ESC]
e.prevent-default!
e.stop-propagation!
@close!
| 38 => # Key[↑]
if @select != -1
e.prevent-default!
e.stop-propagation!
@select-prev!
else
@close!
| 9, 40 => # Key[TAB] or Key[↓]
e.prevent-default!
e.stop-propagation!
@select-next!
| _ =>
@close!
@apply-select!
@select-next = ~>
@select++
@select-prev = ~>
@select--
if @select >= @users.length
@select = 0
if @select < 0
@select = @users.length - 1
@apply-select!
@apply-select!
@select-prev = ~>
@select--
@apply-select = ~>
@refs.users.children.for-each (el) ~>
el.remove-attribute \data-selected
if @select < 0
@select = @users.length - 1
@refs.users.children[@select].set-attribute \data-selected \true
@refs.users.children[@select].focus!
@apply-select!
@complete = (user) ~>
@opts.complete user
@apply-select = ~>
@refs.users.children.for-each (el) ~>
el.remove-attribute \data-selected
@close = ~>
@opts.close!
@refs.users.children[@select].set-attribute \data-selected \true
@refs.users.children[@select].focus!
function contains(parent, child)
node = child.parent-node
while node?
if node == parent
return true
node = node.parent-node
return false
@complete = (user) ~>
@opts.complete user
@close = ~>
@opts.close!
function contains(parent, child)
node = child.parent-node
while node?
if node == parent
return true
node = node.parent-node
return false
</script>
</mk-autocomplete-suggestion>

View File

@ -1,134 +1,127 @@
mk-big-follow-button
button(if={ !init }, class={ wait: wait, follow: !user.is_following, unfollow: user.is_following },
onclick={ onclick },
disabled={ wait },
title={ user.is_following ? 'フォロー解除' : 'フォローする' })
span(if={ !wait && user.is_following })
i.fa.fa-minus
| フォロー解除
span(if={ !wait && !user.is_following })
i.fa.fa-plus
| フォロー
i.fa.fa-spinner.fa-pulse.fa-fw(if={ wait })
div.init(if={ init }): i.fa.fa-spinner.fa-pulse.fa-fw
<mk-big-follow-button>
<button class="{ wait: wait, follow: !user.is_following, unfollow: user.is_following }" if="{ !init }" onclick="{ onclick }" disabled="{ wait }" title="{ user.is_following ? 'フォロー解除' : 'フォローする' }"><span if="{ !wait &amp;&amp; user.is_following }"><i class="fa fa-minus"></i>フォロー解除</span><span if="{ !wait &amp;&amp; !user.is_following }"><i class="fa fa-plus"></i>フォロー</span><i class="fa fa-spinner fa-pulse fa-fw" if="{ wait }"></i></button>
<div class="init" if="{ init }"><i class="fa fa-spinner fa-pulse fa-fw"></i></div>
<style type="stylus">
:scope
display block
style.
display block
> button
> .init
display block
cursor pointer
padding 0
margin 0
width 100%
line-height 38px
font-size 1em
outline none
border-radius 4px
> button
> .init
display block
cursor pointer
padding 0
margin 0
width 100%
line-height 38px
font-size 1em
outline none
border-radius 4px
*
pointer-events none
*
pointer-events none
i
margin-right 8px
i
margin-right 8px
&: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
&: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
&.follow
color #888
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
border solid 1px #e2e2e2
&.follow
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
&:hover
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
border-color #dcdcdc
&:active
background #ececec
border-color #dcdcdc
&:active
background #ececec
border-color #dcdcdc
&.unfollow
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%)
&.unfollow
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
&: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
&: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
&:active:not(:disabled)
background $theme-color
border-color $theme-color
&.wait
cursor wait !important
opacity 0.7
&.wait
cursor wait !important
opacity 0.7
</style>
<script>
@mixin \api
@mixin \is-promise
@mixin \stream
script.
@mixin \api
@mixin \is-promise
@mixin \stream
@user = null
@user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user
@init = true
@wait = false
@user = null
@user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user
@init = true
@wait = false
@on \mount ~>
@user-promise.then (user) ~>
@user = user
@init = false
@update!
@stream.on \follow @on-stream-follow
@stream.on \unfollow @on-stream-unfollow
@on \unmount ~>
@stream.off \follow @on-stream-follow
@stream.off \unfollow @on-stream-unfollow
@on-stream-follow = (user) ~>
if user.id == @user.id
@user = user
@update!
@on-stream-unfollow = (user) ~>
if user.id == @user.id
@user = user
@update!
@onclick = ~>
@wait = true
if @user.is_following
@api \following/delete do
user_id: @user.id
.then ~>
@user.is_following = false
.catch (err) ->
console.error err
.then ~>
@wait = false
@on \mount ~>
@user-promise.then (user) ~>
@user = user
@init = false
@update!
else
@api \following/create do
user_id: @user.id
.then ~>
@user.is_following = true
.catch (err) ->
console.error err
.then ~>
@wait = false
@stream.on \follow @on-stream-follow
@stream.on \unfollow @on-stream-unfollow
@on \unmount ~>
@stream.off \follow @on-stream-follow
@stream.off \unfollow @on-stream-unfollow
@on-stream-follow = (user) ~>
if user.id == @user.id
@user = user
@update!
@on-stream-unfollow = (user) ~>
if user.id == @user.id
@user = user
@update!
@onclick = ~>
@wait = true
if @user.is_following
@api \following/delete do
user_id: @user.id
.then ~>
@user.is_following = false
.catch (err) ->
console.error err
.then ~>
@wait = false
@update!
else
@api \following/create do
user_id: @user.id
.then ~>
@user.is_following = true
.catch (err) ->
console.error err
.then ~>
@wait = false
@update!
</script>
</mk-big-follow-button>

View File

@ -1,138 +1,139 @@
mk-contextmenu
| <yield />
<mk-contextmenu><yield />
<style type="stylus">
:scope
$width = 240px
$item-height = 38px
$padding = 10px
style.
$width = 240px
$item-height = 38px
$padding = 10px
display none
position fixed
top 0
left 0
z-index 4096
width $width
font-size 0.8em
background #fff
border-radius 0 4px 4px 4px
box-shadow 2px 2px 8px rgba(0, 0, 0, 0.2)
display none
position fixed
top 0
left 0
z-index 4096
width $width
font-size 0.8em
background #fff
border-radius 0 4px 4px 4px
box-shadow 2px 2px 8px rgba(0, 0, 0, 0.2)
ul
display block
margin 0
padding $padding 0
list-style none
ul
display block
margin 0
padding $padding 0
list-style none
li
display block
li
display block
&.separator
margin-top $padding
padding-top $padding
border-top solid 1px #eee
&.separator
margin-top $padding
padding-top $padding
border-top solid 1px #eee
&.has-child
> p
cursor default
&.has-child
> p
cursor default
> i:last-child
position absolute
top 0
right 8px
line-height $item-height
> i:last-child
position absolute
top 0
right 8px
line-height $item-height
&:hover > ul
visibility visible
&:hover > ul
visibility visible
&:active
> p, a
background $theme-color
&:active
> p, a
background $theme-color
display block
z-index 1
margin 0
padding 0 32px 0 38px
line-height $item-height
color #868C8C
text-decoration none
cursor pointer
> p, a
display block
z-index 1
margin 0
padding 0 32px 0 38px
line-height $item-height
color #868C8C
text-decoration none
cursor pointer
&:hover
text-decoration none
&:hover
text-decoration none
*
pointer-events none
*
pointer-events none
> i
width 28px
margin-left -28px
text-align center
> i
width 28px
margin-left -28px
text-align center
&:hover
> p, a
text-decoration none
background $theme-color
color $theme-color-foreground
&:hover
> p, a
text-decoration none
background $theme-color
color $theme-color-foreground
&:active
> p, a
text-decoration none
background darken($theme-color, 10%)
color $theme-color-foreground
&:active
> p, a
text-decoration none
background darken($theme-color, 10%)
color $theme-color-foreground
li > ul
visibility hidden
position absolute
top 0
left $width
margin-top -($padding)
width $width
background #fff
border-radius 0 4px 4px 4px
box-shadow 2px 2px 8px rgba(0, 0, 0, 0.2)
transition visibility 0s linear 0.2s
li > ul
visibility hidden
position absolute
top 0
left $width
margin-top -($padding)
width $width
background #fff
border-radius 0 4px 4px 4px
box-shadow 2px 2px 8px rgba(0, 0, 0, 0.2)
transition visibility 0s linear 0.2s
</style>
<script>
@root.add-event-listener \contextmenu (e) ~>
e.prevent-default!
script.
@mousedown = (e) ~>
e.prevent-default!
if (!contains @root, e.target) and (@root != e.target)
@close!
return false
@root.add-event-listener \contextmenu (e) ~>
e.prevent-default!
@open = (pos) ~>
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.add-event-listener \mousedown @mousedown
@root.style.display = \block
@root.style.left = pos.x + \px
@root.style.top = pos.y + \px
@mousedown = (e) ~>
e.prevent-default!
if (!contains @root, e.target) and (@root != e.target)
@close!
return false
Velocity @root, \finish true
Velocity @root, { opacity: 0 } 0ms
Velocity @root, {
opacity: 1
} {
queue: false
duration: 100ms
easing: \linear
}
@open = (pos) ~>
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.add-event-listener \mousedown @mousedown
@root.style.display = \block
@root.style.left = pos.x + \px
@root.style.top = pos.y + \px
@close = ~>
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.remove-event-listener \mousedown @mousedown
@trigger \closed
@unmount!
Velocity @root, \finish true
Velocity @root, { opacity: 0 } 0ms
Velocity @root, {
opacity: 1
} {
queue: false
duration: 100ms
easing: \linear
}
@close = ~>
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.remove-event-listener \mousedown @mousedown
@trigger \closed
@unmount!
function contains(parent, child)
node = child.parent-node
while (node != null)
if (node == parent)
return true
node = node.parent-node
return false
function contains(parent, child)
node = child.parent-node
while (node != null)
if (node == parent)
return true
node = node.parent-node
return false
</script>
</mk-contextmenu>

View File

@ -1,189 +1,188 @@
mk-crop-window
mk-window@window(is-modal={ true }, width={ '800px' })
<yield to="header">
i.fa.fa-crop
| { parent.title }
</yield>
<yield to="content">
div.body
img@img(src={ parent.image.url + '?thumbnail&quality=80' }, alt='')
div.action
button.skip(onclick={ parent.skip }) クロップをスキップ
button.cancel(onclick={ parent.cancel }) キャンセル
button.ok(onclick={ parent.ok }) 決定
</yield>
<mk-crop-window>
<mk-window ref="window" is-modal="{ true }" width="{ '800px' }"><yield to="header"><i class="fa fa-crop"></i>{ parent.title }</yield>
<yield to="content">
<div class="body"><img ref="img" src="{ parent.image.url + '?thumbnail&amp;quality=80' }" alt=""/></div>
<div class="action">
<button class="skip" onclick="{ parent.skip }">クロップをスキップ</button>
<button class="cancel" onclick="{ parent.cancel }">キャンセル</button>
<button class="ok" onclick="{ parent.ok }">決定</button>
</div></yield>
</mk-window>
<style type="stylus">
:scope
display block
style.
display block
> mk-window
[data-yield='header']
> i
margin-right 4px
> mk-window
[data-yield='header']
> i
margin-right 4px
[data-yield='content']
[data-yield='content']
> .body
> img
width 100%
max-height 400px
> .body
> img
width 100%
max-height 400px
.cropper-modal {
opacity: 0.8;
}
.cropper-modal {
opacity: 0.8;
}
.cropper-view-box {
outline-color: $theme-color;
}
.cropper-view-box {
outline-color: $theme-color;
}
.cropper-line, .cropper-point {
background-color: $theme-color;
}
.cropper-line, .cropper-point {
background-color: $theme-color;
}
.cropper-bg {
animation: cropper-bg 0.5s linear infinite;
}
.cropper-bg {
animation: cropper-bg 0.5s linear infinite;
}
@-webkit-keyframes cropper-bg {
0% {
background-position: 0 0;
}
@-webkit-keyframes cropper-bg {
0% {
background-position: 0 0;
}
100% {
background-position: -8px -8px;
}
}
100% {
background-position: -8px -8px;
}
}
@-moz-keyframes cropper-bg {
0% {
background-position: 0 0;
}
@-moz-keyframes cropper-bg {
0% {
background-position: 0 0;
}
100% {
background-position: -8px -8px;
}
}
100% {
background-position: -8px -8px;
}
}
@-ms-keyframes cropper-bg {
0% {
background-position: 0 0;
}
@-ms-keyframes cropper-bg {
0% {
background-position: 0 0;
}
100% {
background-position: -8px -8px;
}
}
100% {
background-position: -8px -8px;
}
}
@keyframes cropper-bg {
0% {
background-position: 0 0;
}
@keyframes cropper-bg {
0% {
background-position: 0 0;
}
100% {
background-position: -8px -8px;
}
}
100% {
background-position: -8px -8px;
}
}
> .action
height 72px
background lighten($theme-color, 95%)
> .action
height 72px
background lighten($theme-color, 95%)
.ok
.cancel
.skip
display block
position absolute
bottom 16px
cursor pointer
padding 0
margin 0
height 40px
font-size 1em
outline none
border-radius 4px
&:focus
&:after
content ""
pointer-events none
.ok
.cancel
.skip
display block
position absolute
top -5px
right -5px
bottom -5px
left -5px
border 2px solid rgba($theme-color, 0.3)
border-radius 8px
bottom 16px
cursor pointer
padding 0
margin 0
height 40px
font-size 1em
outline none
border-radius 4px
&:disabled
opacity 0.7
cursor default
&: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
width 120px
&: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%)
.ok
.cancel
width 120px
&:not(:disabled)
font-weight bold
.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%)
&:hover:not(:disabled)
background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%)
border-color $theme-color
&:not(:disabled)
font-weight bold
&:active:not(:disabled)
background $theme-color
border-color $theme-color
&:hover:not(:disabled)
background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%)
border-color $theme-color
.cancel
.skip
color #888
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
border solid 1px #e2e2e2
&:active:not(:disabled)
background $theme-color
border-color $theme-color
&:hover
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
border-color #dcdcdc
.cancel
.skip
color #888
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
border solid 1px #e2e2e2
&:active
background #ececec
border-color #dcdcdc
&:hover
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
border-color #dcdcdc
.cancel
right 148px
&:active
background #ececec
border-color #dcdcdc
.skip
left 16px
width 150px
.cancel
right 148px
script.
@mixin \cropper
.skip
left 16px
width 150px
@image = @opts.file
@title = @opts.title
@aspect-ratio = @opts.aspect-ratio
@cropper = null
</style>
<script>
@mixin \cropper
@on \mount ~>
@img = @refs.window.refs.img
@cropper = new @Cropper @img, do
aspect-ratio: @aspect-ratio
highlight: no
view-mode: 1
@image = @opts.file
@title = @opts.title
@aspect-ratio = @opts.aspect-ratio
@cropper = null
@ok = ~>
@cropper.get-cropped-canvas!.to-blob (blob) ~>
@trigger \cropped blob
@on \mount ~>
@img = @refs.window.refs.img
@cropper = new @Cropper @img, do
aspect-ratio: @aspect-ratio
highlight: no
view-mode: 1
@ok = ~>
@cropper.get-cropped-canvas!.to-blob (blob) ~>
@trigger \cropped blob
@refs.window.close!
@skip = ~>
@trigger \skiped
@refs.window.close!
@skip = ~>
@trigger \skiped
@refs.window.close!
@cancel = ~>
@trigger \canceled
@refs.window.close!
@cancel = ~>
@trigger \canceled
@refs.window.close!
</script>
</mk-crop-window>

View File

@ -1,87 +1,90 @@
mk-debugger
mk-window@window(is-modal={ false }, width={ '700px' }, height={ '550px' })
<yield to="header">
i.fa.fa-wrench
| Debugger
</yield>
<yield to="content">
section.progress-dialog
h1 progress-dialog
button.style-normal(onclick={ parent.progress-dialog }): i.fa.fa-play
button.style-normal(onclick={ parent.progress-dialog-destroy }): i.fa.fa-stop
label
p TITLE:
input@progress-title(value='Title')
label
p VAL:
input@progress-value(type='number', oninput={ parent.progress-change }, value=0)
label
p MAX:
input@progress-max(type='number', oninput={ parent.progress-change }, value=100)
</yield>
<mk-debugger>
<mk-window ref="window" is-modal="{ false }" width="{ '700px' }" height="{ '550px' }"><yield to="header"><i class="fa fa-wrench"></i>Debugger</yield>
<yield to="content">
<section class="progress-dialog">
<h1>progress-dialog</h1>
<button class="style-normal" onclick="{ parent.progressDialog }"><i class="fa fa-play"></i></button>
<button class="style-normal" onclick="{ parent.progressDialogDestroy }"><i class="fa fa-stop"></i></button>
<label>
<p>TITLE:</p>
<input ref="progressTitle" value="Title"/>
</label>
<label>
<p>VAL:</p>
<input ref="progressValue" type="number" oninput="{ parent.progressChange }" value="0"/>
</label>
<label>
<p>MAX:</p>
<input ref="progressMax" type="number" oninput="{ parent.progressChange }" value="100"/>
</label>
</section></yield>
</mk-window>
<style type="stylus">
:scope
> mk-window
[data-yield='header']
> i
margin-right 4px
style.
> mk-window
[data-yield='header']
> i
margin-right 4px
[data-yield='content']
overflow auto
[data-yield='content']
overflow auto
> section
padding 32px
> section
padding 32px
// & + section
// margin-top 16px
// & + section
// margin-top 16px
> h1
display block
margin 0
padding 0 0 8px 0
font-size 1em
color #555
border-bottom solid 1px #eee
> h1
display block
margin 0
padding 0 0 8px 0
font-size 1em
color #555
border-bottom solid 1px #eee
> label
display block
> label
display block
> p
display inline
margin 0
> p
display inline
margin 0
> .progress-dialog
button
display inline-block
margin 8px
> .progress-dialog
button
display inline-block
margin 8px
</style>
<script>
@mixin \open-window
script.
@mixin \open-window
@on \mount ~>
@progress-title = @tags['mk-window'].progress-title
@progress-value = @tags['mk-window'].progress-value
@progress-max = @tags['mk-window'].progress-max
@on \mount ~>
@progress-title = @tags['mk-window'].progress-title
@progress-value = @tags['mk-window'].progress-value
@progress-max = @tags['mk-window'].progress-max
@refs.window.on \closed ~>
@unmount!
@refs.window.on \closed ~>
@unmount!
################################
################################
@progress-controller = riot.observable!
@progress-controller = riot.observable!
@progress-dialog = ~>
@open-window \mk-progress-dialog do
title: @progress-title.value
value: @progress-value.value
max: @progress-max.value
controller: @progress-controller
@progress-dialog = ~>
@open-window \mk-progress-dialog do
title: @progress-title.value
value: @progress-value.value
max: @progress-max.value
controller: @progress-controller
@progress-change = ~>
@progress-controller.trigger do
\update
@progress-value.value
@progress-max.value
@progress-change = ~>
@progress-controller.trigger do
\update
@progress-value.value
@progress-max.value
@progress-dialog-destroy = ~>
@progress-controller.trigger \close
@progress-dialog-destroy = ~>
@progress-controller.trigger \close
</script>
</mk-debugger>

View File

@ -1,56 +1,60 @@
mk-detect-slow-internet-connection-notice
i: i.fa.fa-exclamation
div: p インターネット回線が遅いようです。
style.
display block
pointer-events none
position fixed
z-index 16384
top 64px
right 16px
margin 0
padding 0
width 298px
font-size 0.9em
background #fff
box-shadow 0 1px 4px rgba(0, 0, 0, 0.25)
opacity 0
> i
display block
width 48px
line-height 48px
margin-right 0.25em
text-align center
color $theme-color-foreground
font-size 1.5em
background $theme-color
> div
display block
position absolute
top 0
left 48px
margin 0
width 250px
height 48px
color #666
> p
<mk-detect-slow-internet-connection-notice><i><i class="fa fa-exclamation"></i></i>
<div>
<p>インターネット回線が遅いようです。</p>
</div>
<style type="stylus">
:scope
display block
pointer-events none
position fixed
z-index 16384
top 64px
right 16px
margin 0
padding 8px
padding 0
width 298px
font-size 0.9em
background #fff
box-shadow 0 1px 4px rgba(0, 0, 0, 0.25)
opacity 0
script.
@mixin \net
> i
display block
width 48px
line-height 48px
margin-right 0.25em
text-align center
color $theme-color-foreground
font-size 1.5em
background $theme-color
@net.on \detected-slow-network ~>
Velocity @root, {
opacity: 1
} 200ms \linear
set-timeout ~>
> div
display block
position absolute
top 0
left 48px
margin 0
width 250px
height 48px
color #666
> p
display block
margin 0
padding 8px
</style>
<script>
@mixin \net
@net.on \detected-slow-network ~>
Velocity @root, {
opacity: 0
opacity: 1
} 200ms \linear
, 10000ms
set-timeout ~>
Velocity @root, {
opacity: 0
} 200ms \linear
, 10000ms
</script>
</mk-detect-slow-internet-connection-notice>

View File

@ -1,141 +1,147 @@
mk-dialog
div.bg@bg(onclick={ bg-click })
div.main@main
header@header
div.body@body
div.buttons
virtual(each={ opts.buttons })
button(onclick={ _onclick }) { text }
<mk-dialog>
<div class="bg" ref="bg" onclick="{ bgClick }"></div>
<div class="main" ref="main">
<header ref="header"></header>
<div class="body" ref="body"></div>
<div class="buttons">
<virtual each="{ opts.buttons }">
<button onclick="{ _onclick }">{ text }</button>
</virtual>
</div>
</div>
<style type="stylus">
:scope
display block
style.
display block
> .bg
display block
position fixed
z-index 8192
top 0
left 0
width 100%
height 100%
background rgba(0, 0, 0, 0.7)
opacity 0
pointer-events none
> .bg
display block
position fixed
z-index 8192
top 0
left 0
width 100%
height 100%
background rgba(0, 0, 0, 0.7)
opacity 0
pointer-events none
> .main
display block
position fixed
z-index 8192
top 20%
left 0
right 0
margin 0 auto 0 auto
padding 32px 42px
width 480px
background #fff
> .main
display block
position fixed
z-index 8192
top 20%
left 0
right 0
margin 0 auto 0 auto
padding 32px 42px
width 480px
background #fff
> header
margin 1em 0
color $theme-color
// color #43A4EC
font-weight bold
> i
margin-right 0.5em
> .body
margin 1em 0
color #888
> .buttons
> button
display inline-block
float right
margin 0
padding 10px 10px
font-size 1.1em
font-weight normal
text-decoration none
color #888
background transparent
outline none
border none
border-radius 0
cursor pointer
transition color 0.1s ease
i
margin 0 0.375em
&:hover
> header
margin 1em 0
color $theme-color
// color #43A4EC
font-weight bold
&:active
color darken($theme-color, 10%)
transition color 0s ease
> i
margin-right 0.5em
script.
@can-through = if opts.can-through? then opts.can-through else true
@opts.buttons.for-each (button) ~>
button._onclick = ~>
if button.onclick?
button.onclick!
@close!
> .body
margin 1em 0
color #888
@on \mount ~>
@refs.header.innerHTML = @opts.title
@refs.body.innerHTML = @opts.text
> .buttons
> button
display inline-block
float right
margin 0
padding 10px 10px
font-size 1.1em
font-weight normal
text-decoration none
color #888
background transparent
outline none
border none
border-radius 0
cursor pointer
transition color 0.1s ease
@refs.bg.style.pointer-events = \auto
Velocity @refs.bg, \finish true
Velocity @refs.bg, {
opacity: 1
} {
queue: false
duration: 100ms
easing: \linear
}
i
margin 0 0.375em
Velocity @refs.main, {
opacity: 0
scale: 1.2
} {
duration: 0
}
Velocity @refs.main, {
opacity: 1
scale: 1
} {
duration: 300ms
easing: [ 0, 0.5, 0.5, 1 ]
}
&:hover
color $theme-color
@close = ~>
@refs.bg.style.pointer-events = \none
Velocity @refs.bg, \finish true
Velocity @refs.bg, {
opacity: 0
} {
queue: false
duration: 300ms
easing: \linear
}
&:active
color darken($theme-color, 10%)
transition color 0s ease
@refs.main.style.pointer-events = \none
Velocity @refs.main, \finish true
Velocity @refs.main, {
opacity: 0
scale: 0.8
} {
queue: false
duration: 300ms
easing: [ 0.5, -0.5, 1, 0.5 ]
complete: ~>
@unmount!
}
</style>
<script>
@can-through = if opts.can-through? then opts.can-through else true
@opts.buttons.for-each (button) ~>
button._onclick = ~>
if button.onclick?
button.onclick!
@close!
@bg-click = ~>
if @can-through
if @opts.on-through?
@opts.on-through!
@close!
@on \mount ~>
@refs.header.innerHTML = @opts.title
@refs.body.innerHTML = @opts.text
@refs.bg.style.pointer-events = \auto
Velocity @refs.bg, \finish true
Velocity @refs.bg, {
opacity: 1
} {
queue: false
duration: 100ms
easing: \linear
}
Velocity @refs.main, {
opacity: 0
scale: 1.2
} {
duration: 0
}
Velocity @refs.main, {
opacity: 1
scale: 1
} {
duration: 300ms
easing: [ 0, 0.5, 0.5, 1 ]
}
@close = ~>
@refs.bg.style.pointer-events = \none
Velocity @refs.bg, \finish true
Velocity @refs.bg, {
opacity: 0
} {
queue: false
duration: 300ms
easing: \linear
}
@refs.main.style.pointer-events = \none
Velocity @refs.main, \finish true
Velocity @refs.main, {
opacity: 0
scale: 0.8
} {
queue: false
duration: 300ms
easing: [ 0.5, -0.5, 1, 0.5 ]
complete: ~>
@unmount!
}
@bg-click = ~>
if @can-through
if @opts.on-through?
@opts.on-through!
@close!
</script>
</mk-dialog>

View File

@ -1,63 +1,68 @@
mk-donation
button.close(onclick={ close }) 閉じる x
div.message
p 利用者の皆さま、
p
| 今日は、日本の皆さまにお知らせがあります。
| Misskeyの援助をお願いいたします。
| 私は独立性を守るため、一切の広告を掲載いたしません。
| 平均で約¥1,500の寄付をいただき、運営しております。
| 援助をしてくださる利用者はほんの少数です。
| お願いいたします。
| 今日、利用者の皆さまが¥300ご援助くだされば、募金活動を一時間で終了することができます。
| コーヒー1杯ほどの金額です。
| Misskeyを活用しておられるのでしたら、広告を掲載せずにもう1年活動できるよう、どうか1分だけお時間をください。
| 私は小さな非営利個人ですが、サーバー、プログラム、人件費など、世界でトップクラスのウェブサイト同等のコストがかかります。
| 利用者は何億人といますが、他の大きなサイトに比べてほんの少額の費用で運営しているのです。
| 人間の可能性、自由、そして機会。知識こそ、これらの基盤を成すものです。
| 私は、誰もが無料かつ制限なく知識に触れられるべきだと信じています。
| 募金活動を終了し、Misskeyの改善に戻れるようご援助ください。
| よろしくお願いいたします。
style.
display block
color #fff
background #03072C
> .close
position absolute
top 16px
right 16px
z-index 1
> .message
padding 32px
font-size 1.4em
font-family serif
> p
<mk-donation>
<button class="close" onclick="{ close }">閉じる x</button>
<div class="message">
<p>利用者の皆さま、</p>
<p>
今日は、日本の皆さまにお知らせがあります。
Misskeyの援助をお願いいたします。
私は独立性を守るため、一切の広告を掲載いたしません。
平均で約¥1,500の寄付をいただき、運営しております。
援助をしてくださる利用者はほんの少数です。
お願いいたします。
今日、利用者の皆さまが¥300ご援助くだされば、募金活動を一時間で終了することができます。
コーヒー1杯ほどの金額です。
Misskeyを活用しておられるのでしたら、広告を掲載せずにもう1年活動できるよう、どうか1分だけお時間をください。
私は小さな非営利個人ですが、サーバー、プログラム、人件費など、世界でトップクラスのウェブサイト同等のコストがかかります。
利用者は何億人といますが、他の大きなサイトに比べてほんの少額の費用で運営しているのです。
人間の可能性、自由、そして機会。知識こそ、これらの基盤を成すものです。
私は、誰もが無料かつ制限なく知識に触れられるべきだと信じています。
募金活動を終了し、Misskeyの改善に戻れるようご援助ください。
よろしくお願いいたします。
</p>
</div>
<style type="stylus">
:scope
display block
margin 0 auto
max-width 1200px
color #fff
background #03072C
> p:first-child
margin-bottom 16px
> .close
position absolute
top 16px
right 16px
z-index 1
script.
@mixin \api
@mixin \i
> .message
padding 32px
font-size 1.4em
font-family serif
@close = (e) ~>
e.prevent-default!
e.stop-propagation!
> p
display block
margin 0 auto
max-width 1200px
@I.data.no_donation = true
@api \i/appdata/set do
data: JSON.stringify do
no_donation: @I.data.no_donation
.then ~>
@update-i!
> p:first-child
margin-bottom 16px
@unmount!
</style>
<script>
@mixin \api
@mixin \i
@parent.parent.set-root-layout!
@close = (e) ~>
e.prevent-default!
e.stop-propagation!
@I.data.no_donation = true
@api \i/appdata/set do
data: JSON.stringify do
no_donation: @I.data.no_donation
.then ~>
@update-i!
@unmount!
@parent.parent.set-root-layout!
</script>
</mk-donation>

View File

@ -1,28 +1,31 @@
mk-drive-browser-base-contextmenu
mk-contextmenu@ctx
ul
li(onclick={ parent.create-folder }): p
i.fa.fa-folder-o
| フォルダーを作成
li(onclick={ parent.upload }): p
i.fa.fa-upload
| ファイルをアップロード
<mk-drive-browser-base-contextmenu>
<mk-contextmenu ref="ctx">
<ul>
<li onclick="{ parent.createFolder }">
<p><i class="fa fa-folder-o"></i>フォルダーを作成</p>
</li>
<li onclick="{ parent.upload }">
<p><i class="fa fa-upload"></i>ファイルをアップロード</p>
</li>
</ul>
</mk-contextmenu>
<script>
@browser = @opts.browser
script.
@browser = @opts.browser
@on \mount ~>
@refs.ctx.on \closed ~>
@trigger \closed
@unmount!
@on \mount ~>
@refs.ctx.on \closed ~>
@trigger \closed
@unmount!
@open = (pos) ~>
@refs.ctx.open pos
@open = (pos) ~>
@refs.ctx.open pos
@create-folder = ~>
@browser.create-folder!
@refs.ctx.close!
@create-folder = ~>
@browser.create-folder!
@refs.ctx.close!
@upload = ~>
@browser.select-local-file!
@refs.ctx.close!
@upload = ~>
@browser.select-local-file!
@refs.ctx.close!
</script>
</mk-drive-browser-base-contextmenu>

View File

@ -1,29 +1,28 @@
mk-drive-browser-window
mk-window@window(is-modal={ false }, width={ '800px' }, height={ '500px' })
<yield to="header">
i.fa.fa-cloud
| ドライブ
</yield>
<yield to="content">
mk-drive-browser(multiple={ true }, folder={ parent.folder })
</yield>
<mk-drive-browser-window>
<mk-window ref="window" is-modal="{ false }" width="{ '800px' }" height="{ '500px' }"><yield to="header"><i class="fa fa-cloud"></i>ドライブ</yield>
<yield to="content">
<mk-drive-browser multiple="{ true }" folder="{ parent.folder }"></mk-drive-browser></yield>
</mk-window>
<style type="stylus">
:scope
> mk-window
[data-yield='header']
> i
margin-right 4px
style.
> mk-window
[data-yield='header']
> i
margin-right 4px
[data-yield='content']
> mk-drive-browser
height 100%
[data-yield='content']
> mk-drive-browser
height 100%
</style>
<script>
@folder = if @opts.folder? then @opts.folder else null
script.
@folder = if @opts.folder? then @opts.folder else null
@on \mount ~>
@refs.window.on \closed ~>
@unmount!
@on \mount ~>
@refs.window.on \closed ~>
@unmount!
@close = ~>
@refs.window.close!
@close = ~>
@refs.window.close!
</script>
</mk-drive-browser-window>

File diff suppressed because it is too large Load Diff

View File

@ -1,97 +1,103 @@
mk-drive-browser-file-contextmenu
mk-contextmenu@ctx: ul
li(onclick={ parent.rename }): p
i.fa.fa-i-cursor
| 名前を変更
li(onclick={ parent.copy-url }): p
i.fa.fa-link
| URLをコピー
li: a(href={ parent.file.url + '?download' }, download={ parent.file.name }, onclick={ parent.download })
i.fa.fa-download
| ダウンロード
li.separator
li(onclick={ parent.delete }): p
i.fa.fa-trash-o
| 削除
li.separator
li.has-child
p
| その他...
i.fa.fa-caret-right
ul
li(onclick={ parent.set-avatar }): p
| アバターに設定
li(onclick={ parent.set-banner }): p
| バナーに設定
li(onclick={ parent.set-wallpaper }): p
| 壁紙に設定
li.has-child
p
| アプリで開く...
i.fa.fa-caret-right
ul
li(onclick={ parent.add-app }): p
| アプリを追加...
<mk-drive-browser-file-contextmenu>
<mk-contextmenu ref="ctx">
<ul>
<li onclick="{ parent.rename }">
<p><i class="fa fa-i-cursor"></i>名前を変更</p>
</li>
<li onclick="{ parent.copyUrl }">
<p><i class="fa fa-link"></i>URLをコピー</p>
</li>
<li><a href="{ parent.file.url + '?download' }" download="{ parent.file.name }" onclick="{ parent.download }"><i class="fa fa-download"></i>ダウンロード</a></li>
<li class="separator"></li>
<li onclick="{ parent.delete }">
<p><i class="fa fa-trash-o"></i>削除</p>
</li>
<li class="separator"></li>
<li class="has-child">
<p>その他...<i class="fa fa-caret-right"></i></p>
<ul>
<li onclick="{ parent.setAvatar }">
<p>アバターに設定</p>
</li>
<li onclick="{ parent.setBanner }">
<p>バナーに設定</p>
</li>
<li onclick="{ parent.setWallpaper }">
<p>壁紙に設定</p>
</li>
</ul>
</li>
<li class="has-child">
<p>アプリで開く...<i class="fa fa-caret-right"></i></p>
<ul>
<li onclick="{ parent.addApp }">
<p>アプリを追加...</p>
</li>
</ul>
</li>
</ul>
</mk-contextmenu>
<script>
@mixin \api
@mixin \i
@mixin \update-avatar
@mixin \update-banner
@mixin \update-wallpaper
@mixin \input-dialog
@mixin \NotImplementedException
script.
@mixin \api
@mixin \i
@mixin \update-avatar
@mixin \update-banner
@mixin \update-wallpaper
@mixin \input-dialog
@mixin \NotImplementedException
@browser = @opts.browser
@file = @opts.file
@browser = @opts.browser
@file = @opts.file
@on \mount ~>
@refs.ctx.on \closed ~>
@trigger \closed
@unmount!
@on \mount ~>
@refs.ctx.on \closed ~>
@trigger \closed
@unmount!
@open = (pos) ~>
@refs.ctx.open pos
@open = (pos) ~>
@refs.ctx.open pos
@rename = ~>
@refs.ctx.close!
@rename = ~>
@refs.ctx.close!
name <~ @input-dialog do
'ファイル名の変更'
'新しいファイル名を入力してください'
@file.name
name <~ @input-dialog do
'ファイル名の変更'
'新しいファイル名を入力してください'
@file.name
@api \drive/files/update do
file_id: @file.id
name: name
.then ~>
# something
.catch (err) ~>
console.error err
@api \drive/files/update do
file_id: @file.id
name: name
.then ~>
# something
.catch (err) ~>
console.error err
@copy-url = ~>
@NotImplementedException!
@copy-url = ~>
@NotImplementedException!
@download = ~>
@refs.ctx.close!
@download = ~>
@refs.ctx.close!
@set-avatar = ~>
@refs.ctx.close!
@update-avatar @I, (i) ~>
@update-i i
, @file
@set-avatar = ~>
@refs.ctx.close!
@update-avatar @I, (i) ~>
@update-i i
, @file
@set-banner = ~>
@refs.ctx.close!
@update-banner @I, (i) ~>
@update-i i
, @file
@set-banner = ~>
@refs.ctx.close!
@update-banner @I, (i) ~>
@update-i i
, @file
@set-wallpaper = ~>
@refs.ctx.close!
@update-wallpaper @I, (i) ~>
@update-i i
, @file
@set-wallpaper = ~>
@refs.ctx.close!
@update-wallpaper @I, (i) ~>
@update-i i
, @file
@add-app = ~>
@NotImplementedException!
@add-app = ~>
@NotImplementedException!
</script>
</mk-drive-browser-file-contextmenu>

View File

@ -1,207 +1,208 @@
mk-drive-browser-file(data-is-selected={ (file._selected || false).toString() }, data-is-contextmenu-showing={ is-contextmenu-showing.toString() }, onclick={ onclick }, oncontextmenu={ oncontextmenu }, draggable='true', ondragstart={ ondragstart }, ondragend={ ondragend }, title={ title })
div.label(if={ I.avatar_id == file.id })
img(src='/_/resources/label.svg')
p アバター
div.label(if={ I.banner_id == file.id })
img(src='/_/resources/label.svg')
p バナー
div.label(if={ I.data.wallpaper == file.id })
img(src='/_/resources/label.svg')
p 壁紙
div.thumbnail: img(src={ file.url + '?thumbnail&size=128' }, alt='')
p.name
span { file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }
span.ext(if={ file.name.lastIndexOf('.') != -1 }) { file.name.substr(file.name.lastIndexOf('.')) }
style.
display block
margin 4px
padding 8px 0 0 0
width 144px
height 180px
border-radius 4px
&, *
cursor pointer
&:hover
background rgba(0, 0, 0, 0.05)
> .label
&:before
&:after
background #0b65a5
&:active
background rgba(0, 0, 0, 0.1)
> .label
&:before
&:after
background #0b588c
&[data-is-selected='true']
background $theme-color
&:hover
background lighten($theme-color, 10%)
&:active
background darken($theme-color, 10%)
> .label
&:before
&:after
display none
> .name
color $theme-color-foreground
&[data-is-contextmenu-showing='true']
&:after
content ""
pointer-events none
position absolute
top -4px
right -4px
bottom -4px
left -4px
border 2px dashed rgba($theme-color, 0.3)
<mk-drive-browser-file data-is-selected="{ (file._selected || false).toString() }" data-is-contextmenu-showing="{ isContextmenuShowing.toString() }" onclick="{ onclick }" oncontextmenu="{ oncontextmenu }" draggable="true" ondragstart="{ ondragstart }" ondragend="{ ondragend }" title="{ title }">
<div class="label" if="{ I.avatar_id == file.id }"><img src="/_/resources/label.svg"/>
<p>アバター</p>
</div>
<div class="label" if="{ I.banner_id == file.id }"><img src="/_/resources/label.svg"/>
<p>バナー</p>
</div>
<div class="label" if="{ I.data.wallpaper == file.id }"><img src="/_/resources/label.svg"/>
<p>壁紙</p>
</div>
<div class="thumbnail"><img src="{ file.url + '?thumbnail&amp;size=128' }" alt=""/></div>
<p class="name"><span>{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }</span><span class="ext" if="{ file.name.lastIndexOf('.') != -1 }">{ file.name.substr(file.name.lastIndexOf('.')) }</span></p>
<style type="stylus">
:scope
display block
margin 4px
padding 8px 0 0 0
width 144px
height 180px
border-radius 4px
> .label
position absolute
top 0
left 0
pointer-events none
&, *
cursor pointer
&:before
content ""
display block
position absolute
z-index 1
top 0
left 57px
width 28px
height 8px
background #0c7ac9
&:hover
background rgba(0, 0, 0, 0.05)
&:after
content ""
display block
position absolute
z-index 1
top 57px
left 0
width 8px
height 28px
background #0c7ac9
> .label
&:before
&:after
background #0b65a5
> img
position absolute
z-index 2
top 0
left 0
&:active
background rgba(0, 0, 0, 0.1)
> p
position absolute
z-index 3
top 19px
left -28px
width 120px
margin 0
text-align center
line-height 28px
color #fff
transform rotate(-45deg)
> .label
&:before
&:after
background #0b588c
> .thumbnail
width 128px
height 128px
left 8px
&[data-is-selected='true']
background $theme-color
> img
display block
position absolute
top 0
left 0
right 0
bottom 0
margin auto
max-width 128px
max-height 128px
pointer-events none
&:hover
background lighten($theme-color, 10%)
> .name
display block
margin 4px 0 0 0
font-size 0.8em
text-align center
word-break break-all
color #444
overflow hidden
&:active
background darken($theme-color, 10%)
> .ext
opacity 0.5
> .label
&:before
&:after
display none
script.
@mixin \i
@mixin \bytes-to-size
> .name
color $theme-color-foreground
@file = @opts.file
@browser = @parent
&[data-is-contextmenu-showing='true']
&:after
content ""
pointer-events none
position absolute
top -4px
right -4px
bottom -4px
left -4px
border 2px dashed rgba($theme-color, 0.3)
border-radius 4px
@title = @file.name + '\n' + @file.type + ' ' + (@bytes-to-size @file.datasize)
> .label
position absolute
top 0
left 0
pointer-events none
@is-contextmenu-showing = false
&:before
content ""
display block
position absolute
z-index 1
top 0
left 57px
width 28px
height 8px
background #0c7ac9
@onclick = ~>
if @browser.multiple
if @file._selected?
@file._selected = !@file._selected
&:after
content ""
display block
position absolute
z-index 1
top 57px
left 0
width 8px
height 28px
background #0c7ac9
> img
position absolute
z-index 2
top 0
left 0
> p
position absolute
z-index 3
top 19px
left -28px
width 120px
margin 0
text-align center
line-height 28px
color #fff
transform rotate(-45deg)
> .thumbnail
width 128px
height 128px
left 8px
> img
display block
position absolute
top 0
left 0
right 0
bottom 0
margin auto
max-width 128px
max-height 128px
pointer-events none
> .name
display block
margin 4px 0 0 0
font-size 0.8em
text-align center
word-break break-all
color #444
overflow hidden
> .ext
opacity 0.5
</style>
<script>
@mixin \i
@mixin \bytes-to-size
@file = @opts.file
@browser = @parent
@title = @file.name + '\n' + @file.type + ' ' + (@bytes-to-size @file.datasize)
@is-contextmenu-showing = false
@onclick = ~>
if @browser.multiple
if @file._selected?
@file._selected = !@file._selected
else
@file._selected = true
@browser.trigger \change-selection @browser.get-selection!
else
@file._selected = true
@browser.trigger \change-selection @browser.get-selection!
else
if @file._selected
@browser.trigger \selected @file
else
@browser.files.for-each (file) ~>
file._selected = false
@file._selected = true
@browser.trigger \change-selection @file
if @file._selected
@browser.trigger \selected @file
else
@browser.files.for-each (file) ~>
file._selected = false
@file._selected = true
@browser.trigger \change-selection @file
@oncontextmenu = (e) ~>
e.prevent-default!
e.stop-immediate-propagation!
@oncontextmenu = (e) ~>
e.prevent-default!
e.stop-immediate-propagation!
@is-contextmenu-showing = true
@update!
ctx = document.body.append-child document.create-element \mk-drive-browser-file-contextmenu
ctx = riot.mount ctx, do
browser: @browser
file: @file
ctx = ctx.0
ctx.open do
x: e.page-x - window.page-x-offset
y: e.page-y - window.page-y-offset
ctx.on \closed ~>
@is-contextmenu-showing = false
@is-contextmenu-showing = true
@update!
return false
ctx = document.body.append-child document.create-element \mk-drive-browser-file-contextmenu
ctx = riot.mount ctx, do
browser: @browser
file: @file
ctx = ctx.0
ctx.open do
x: e.page-x - window.page-x-offset
y: e.page-y - window.page-y-offset
ctx.on \closed ~>
@is-contextmenu-showing = false
@update!
return false
@ondragstart = (e) ~>
e.data-transfer.effect-allowed = \move
e.data-transfer.set-data 'text' JSON.stringify do
type: \file
id: @file.id
file: @file
@is-dragging = true
@ondragstart = (e) ~>
e.data-transfer.effect-allowed = \move
e.data-transfer.set-data 'text' JSON.stringify do
type: \file
id: @file.id
file: @file
@is-dragging = true
# 親ブラウザに対して、ドラッグが開始されたフラグを立てる
# (=あなたの子供が、ドラッグを開始しましたよ)
@browser.is-drag-source = true
# 親ブラウザに対して、ドラッグが開始されたフラグを立てる
# (=あなたの子供が、ドラッグを開始しましたよ)
@browser.is-drag-source = true
@ondragend = (e) ~>
@is-dragging = false
@browser.is-drag-source = false
@ondragend = (e) ~>
@is-dragging = false
@browser.is-drag-source = false
</script>
</mk-drive-browser-file>

View File

@ -1,62 +1,66 @@
mk-drive-browser-folder-contextmenu
mk-contextmenu@ctx: ul
li(onclick={ parent.move }): p
i.fa.fa-arrow-right
| このフォルダへ移動
li(onclick={ parent.new-window }): p
i.fa.fa-share-square-o
| 新しいウィンドウで表示
li.separator
li(onclick={ parent.rename }): p
i.fa.fa-i-cursor
| 名前を変更
li.separator
li(onclick={ parent.delete }): p
i.fa.fa-trash-o
| 削除
<mk-drive-browser-folder-contextmenu>
<mk-contextmenu ref="ctx">
<ul>
<li onclick="{ parent.move }">
<p><i class="fa fa-arrow-right"></i>このフォルダへ移動</p>
</li>
<li onclick="{ parent.newWindow }">
<p><i class="fa fa-share-square-o"></i>新しいウィンドウで表示</p>
</li>
<li class="separator"></li>
<li onclick="{ parent.rename }">
<p><i class="fa fa-i-cursor"></i>名前を変更</p>
</li>
<li class="separator"></li>
<li onclick="{ parent.delete }">
<p><i class="fa fa-trash-o"></i>削除</p>
</li>
</ul>
</mk-contextmenu>
<script>
@mixin \api
@mixin \input-dialog
script.
@mixin \api
@mixin \input-dialog
@browser = @opts.browser
@folder = @opts.folder
@browser = @opts.browser
@folder = @opts.folder
@open = (pos) ~>
@refs.ctx.open pos
@open = (pos) ~>
@refs.ctx.open pos
@refs.ctx.on \closed ~>
@trigger \closed
@unmount!
@refs.ctx.on \closed ~>
@trigger \closed
@unmount!
@move = ~>
@browser.move @folder.id
@refs.ctx.close!
@move = ~>
@browser.move @folder.id
@refs.ctx.close!
@new-window = ~>
@browser.new-window @folder.id
@refs.ctx.close!
@new-window = ~>
@browser.new-window @folder.id
@refs.ctx.close!
@create-folder = ~>
@browser.create-folder!
@refs.ctx.close!
@create-folder = ~>
@browser.create-folder!
@refs.ctx.close!
@upload = ~>
@browser.select-lcoal-file!
@refs.ctx.close!
@upload = ~>
@browser.select-lcoal-file!
@refs.ctx.close!
@rename = ~>
@refs.ctx.close!
@rename = ~>
@refs.ctx.close!
name <~ @input-dialog do
'フォルダ名の変更'
'新しいフォルダ名を入力してください'
@folder.name
name <~ @input-dialog do
'フォルダ名の変更'
'新しいフォルダ名を入力してください'
@folder.name
@api \drive/folders/update do
folder_id: @folder.id
name: name
.then ~>
# something
.catch (err) ~>
console.error err
@api \drive/folders/update do
folder_id: @folder.id
name: name
.then ~>
# something
.catch (err) ~>
console.error err
</script>
</mk-drive-browser-folder-contextmenu>

View File

@ -1,183 +1,184 @@
mk-drive-browser-folder(data-is-contextmenu-showing={ is-contextmenu-showing.toString() }, data-draghover={ draghover.toString() }, onclick={ onclick }, onmouseover={ onmouseover }, onmouseout={ onmouseout }, ondragover={ ondragover }, ondragenter={ ondragenter }, ondragleave={ ondragleave }, ondrop={ ondrop }, oncontextmenu={ oncontextmenu }, draggable='true', ondragstart={ ondragstart }, ondragend={ ondragend }, title={ title })
p.name
i.fa.fa-fw(class={ fa-folder-o: !hover, fa-folder-open-o: hover })
| { folder.name }
style.
display block
margin 4px
padding 8px
width 144px
height 64px
background lighten($theme-color, 95%)
border-radius 4px
&, *
cursor pointer
*
pointer-events none
&:hover
background lighten($theme-color, 90%)
&:active
background lighten($theme-color, 85%)
&[data-is-contextmenu-showing='true']
&[data-draghover='true']
&:after
content ""
pointer-events none
position absolute
top -4px
right -4px
bottom -4px
left -4px
border 2px dashed rgba($theme-color, 0.3)
<mk-drive-browser-folder data-is-contextmenu-showing="{ isContextmenuShowing.toString() }" data-draghover="{ draghover.toString() }" onclick="{ onclick }" onmouseover="{ onmouseover }" onmouseout="{ onmouseout }" ondragover="{ ondragover }" ondragenter="{ ondragenter }" ondragleave="{ ondragleave }" ondrop="{ ondrop }" oncontextmenu="{ oncontextmenu }" draggable="true" ondragstart="{ ondragstart }" ondragend="{ ondragend }" title="{ title }">
<p class="name"><i class="fa fa-fw { fa-folder-o: !hover, fa-folder-open-o: hover }"></i>{ folder.name }</p>
<style type="stylus">
:scope
display block
margin 4px
padding 8px
width 144px
height 64px
background lighten($theme-color, 95%)
border-radius 4px
&[data-draghover='true']
background lighten($theme-color, 90%)
&, *
cursor pointer
> .name
margin 0
font-size 0.9em
color darken($theme-color, 30%)
*
pointer-events none
> i
margin-right 4px
margin-left 2px
text-align left
&:hover
background lighten($theme-color, 90%)
script.
@mixin \api
@mixin \dialog
&:active
background lighten($theme-color, 85%)
@folder = @opts.folder
@browser = @parent
&[data-is-contextmenu-showing='true']
&[data-draghover='true']
&:after
content ""
pointer-events none
position absolute
top -4px
right -4px
bottom -4px
left -4px
border 2px dashed rgba($theme-color, 0.3)
border-radius 4px
@title = @folder.name
@hover = false
@draghover = false
@is-contextmenu-showing = false
&[data-draghover='true']
background lighten($theme-color, 90%)
@onclick = ~>
@browser.move @folder
> .name
margin 0
font-size 0.9em
color darken($theme-color, 30%)
@onmouseover = ~>
@hover = true
> i
margin-right 4px
margin-left 2px
text-align left
@onmouseout = ~>
</style>
<script>
@mixin \api
@mixin \dialog
@folder = @opts.folder
@browser = @parent
@title = @folder.name
@hover = false
@draghover = false
@is-contextmenu-showing = false
@ondragover = (e) ~>
e.prevent-default!
e.stop-propagation!
@onclick = ~>
@browser.move @folder
# 自分自身がドラッグされていない場合
if !@is-dragging
# ドラッグされてきたものがファイルだったら
if e.data-transfer.effect-allowed == \all
e.data-transfer.drop-effect = \copy
@onmouseover = ~>
@hover = true
@onmouseout = ~>
@hover = false
@ondragover = (e) ~>
e.prevent-default!
e.stop-propagation!
# 自分自身がドラッグされていない場合
if !@is-dragging
# ドラッグされてきたものがファイルだったら
if e.data-transfer.effect-allowed == \all
e.data-transfer.drop-effect = \copy
else
e.data-transfer.drop-effect = \move
else
e.data-transfer.drop-effect = \move
else
# 自分自身にはドロップさせない
e.data-transfer.drop-effect = \none
return false
@ondragenter = ~>
if !@is-dragging
@draghover = true
@ondragleave = ~>
@draghover = false
@ondrop = (e) ~>
e.stop-propagation!
@draghover = false
# ファイルだったら
if e.data-transfer.files.length > 0
Array.prototype.for-each.call e.data-transfer.files, (file) ~>
@browser.upload file, @folder
# 自分自身にはドロップさせない
e.data-transfer.drop-effect = \none
return false
# データ取得
data = e.data-transfer.get-data 'text'
if !data?
return false
@ondragenter = ~>
if !@is-dragging
@draghover = true
# パース
obj = JSON.parse data
@ondragleave = ~>
@draghover = false
# (ドライブの)ファイルだったら
if obj.type == \file
file = obj.id
@browser.remove-file file
@api \drive/files/update do
file_id: file
folder_id: @folder.id
.then ~>
# something
.catch (err, text-status) ~>
console.error err
@ondrop = (e) ~>
e.stop-propagation!
@draghover = false
# (ドライブの)フォルダーだったら
else if obj.type == \folder
folder = obj.id
# 移動先が自分自身ならreject
if folder == @folder.id
# ファイルだったら
if e.data-transfer.files.length > 0
Array.prototype.for-each.call e.data-transfer.files, (file) ~>
@browser.upload file, @folder
return false
@browser.remove-folder folder
@api \drive/folders/update do
folder_id: folder
parent_id: @folder.id
.then ~>
# something
.catch (err) ~>
if err == 'detected-circular-definition'
@dialog do
'<i class="fa fa-exclamation-triangle"></i>操作を完了できません'
'移動先のフォルダーは、移動するフォルダーのサブフォルダーです。'
[
text: \OK
]
return false
# データ取得
data = e.data-transfer.get-data 'text'
if !data?
return false
@ondragstart = (e) ~>
e.data-transfer.effect-allowed = \move
e.data-transfer.set-data 'text' JSON.stringify do
type: \folder
id: @folder.id
@is-dragging = true
# パース
obj = JSON.parse data
# 親ブラウザに対して、ドラッグが開始されたフラグを立てる
# (=あなたの子供が、ドラッグを開始しましたよ)
@browser.is-drag-source = true
# (ドライブの)ファイルだったら
if obj.type == \file
file = obj.id
@browser.remove-file file
@api \drive/files/update do
file_id: file
folder_id: @folder.id
.then ~>
# something
.catch (err, text-status) ~>
console.error err
@ondragend = (e) ~>
@is-dragging = false
@browser.is-drag-source = false
# (ドライブの)フォルダーだったら
else if obj.type == \folder
folder = obj.id
# 移動先が自分自身ならreject
if folder == @folder.id
return false
@browser.remove-folder folder
@api \drive/folders/update do
folder_id: folder
parent_id: @folder.id
.then ~>
# something
.catch (err) ~>
if err == 'detected-circular-definition'
@dialog do
'<i class="fa fa-exclamation-triangle"></i>操作を完了できません'
'移動先のフォルダーは、移動するフォルダーのサブフォルダーです。'
[
text: \OK
]
@oncontextmenu = (e) ~>
e.prevent-default!
e.stop-immediate-propagation!
return false
@is-contextmenu-showing = true
@update!
ctx = document.body.append-child document.create-element \mk-drive-browser-folder-contextmenu
ctx = riot.mount ctx, do
browser: @browser
folder: @folder
ctx = ctx.0
ctx.open do
x: e.page-x - window.page-x-offset
y: e.page-y - window.page-y-offset
ctx.on \closed ~>
@is-contextmenu-showing = false
@ondragstart = (e) ~>
e.data-transfer.effect-allowed = \move
e.data-transfer.set-data 'text' JSON.stringify do
type: \folder
id: @folder.id
@is-dragging = true
# 親ブラウザに対して、ドラッグが開始されたフラグを立てる
# (=あなたの子供が、ドラッグを開始しましたよ)
@browser.is-drag-source = true
@ondragend = (e) ~>
@is-dragging = false
@browser.is-drag-source = false
@oncontextmenu = (e) ~>
e.prevent-default!
e.stop-immediate-propagation!
@is-contextmenu-showing = true
@update!
ctx = document.body.append-child document.create-element \mk-drive-browser-folder-contextmenu
ctx = riot.mount ctx, do
browser: @browser
folder: @folder
ctx = ctx.0
ctx.open do
x: e.page-x - window.page-x-offset
y: e.page-y - window.page-y-offset
ctx.on \closed ~>
@is-contextmenu-showing = false
@update!
return false
return false
</script>
</mk-drive-browser-folder>

View File

@ -1,96 +1,97 @@
mk-drive-browser-nav-folder(data-draghover={ draghover }, onclick={ onclick }, ondragover={ ondragover }, ondragenter={ ondragenter }, ondragleave={ ondragleave }, ondrop={ ondrop })
i.fa.fa-cloud(if={ folder == null })
span { folder == null ? 'ドライブ' : folder.name }
<mk-drive-browser-nav-folder data-draghover="{ draghover }" onclick="{ onclick }" ondragover="{ ondragover }" ondragenter="{ ondragenter }" ondragleave="{ ondragleave }" ondrop="{ ondrop }"><i class="fa fa-cloud" if="{ folder == null }"></i><span>{ folder == null ? 'ドライブ' : folder.name }</span>
<style type="stylus">
:scope
&[data-draghover]
background #eee
style.
&[data-draghover]
background #eee
</style>
<script>
@mixin \api
script.
@mixin \api
# Riotのバグでnullを渡しても""になる
# https://github.com/riot/riot/issues/2080
#@folder = @opts.folder
@folder = if @opts.folder? and @opts.folder != '' then @opts.folder else null
@browser = @parent
# Riotのバグでnullを渡しても""になる
# https://github.com/riot/riot/issues/2080
#@folder = @opts.folder
@folder = if @opts.folder? and @opts.folder != '' then @opts.folder else null
@browser = @parent
@hover = false
@onclick = ~>
@browser.move @folder
@onmouseover = ~>
@hover = true
@onmouseout = ~>
@hover = false
@ondragover = (e) ~>
e.prevent-default!
e.stop-propagation!
@onclick = ~>
@browser.move @folder
# このフォルダがルートかつカレントディレクトリならドロップ禁止
if @folder == null and @browser.folder == null
e.data-transfer.drop-effect = \none
# ドラッグされてきたものがファイルだったら
else if e.data-transfer.effect-allowed == \all
e.data-transfer.drop-effect = \copy
else
e.data-transfer.drop-effect = \move
return false
@onmouseover = ~>
@hover = true
@ondragenter = ~>
if @folder != null or @browser.folder != null
@draghover = true
@onmouseout = ~>
@hover = false
@ondragleave = ~>
if @folder != null or @browser.folder != null
@ondragover = (e) ~>
e.prevent-default!
e.stop-propagation!
# このフォルダがルートかつカレントディレクトリならドロップ禁止
if @folder == null and @browser.folder == null
e.data-transfer.drop-effect = \none
# ドラッグされてきたものがファイルだったら
else if e.data-transfer.effect-allowed == \all
e.data-transfer.drop-effect = \copy
else
e.data-transfer.drop-effect = \move
return false
@ondragenter = ~>
if @folder != null or @browser.folder != null
@draghover = true
@ondragleave = ~>
if @folder != null or @browser.folder != null
@draghover = false
@ondrop = (e) ~>
e.stop-propagation!
@draghover = false
@ondrop = (e) ~>
e.stop-propagation!
@draghover = false
# ファイルだったら
if e.data-transfer.files.length > 0
Array.prototype.for-each.call e.data-transfer.files, (file) ~>
@browser.upload file, @folder
return false
# データ取得
data = e.data-transfer.get-data 'text'
if !data?
return false
# パース
obj = JSON.parse data
# (ドライブの)ファイルだったら
if obj.type == \file
file = obj.id
@browser.remove-file file
@api \drive/files/update do
file_id: file
folder_id: if @folder? then @folder.id else null
.then ~>
# something
.catch (err, text-status) ~>
console.error err
# (ドライブの)フォルダーだったら
else if obj.type == \folder
folder = obj.id
# 移動先が自分自身ならreject
if @folder? and folder == @folder.id
# ファイルだったら
if e.data-transfer.files.length > 0
Array.prototype.for-each.call e.data-transfer.files, (file) ~>
@browser.upload file, @folder
return false
@browser.remove-folder folder
@api \drive/folders/update do
folder_id: folder
parent_id: if @folder? then @folder.id else null
.then ~>
# something
.catch (err, text-status) ~>
console.error err
return false
# データ取得
data = e.data-transfer.get-data 'text'
if !data?
return false
# パース
obj = JSON.parse data
# (ドライブの)ファイルだったら
if obj.type == \file
file = obj.id
@browser.remove-file file
@api \drive/files/update do
file_id: file
folder_id: if @folder? then @folder.id else null
.then ~>
# something
.catch (err, text-status) ~>
console.error err
# (ドライブの)フォルダーだったら
else if obj.type == \folder
folder = obj.id
# 移動先が自分自身ならreject
if @folder? and folder == @folder.id
return false
@browser.remove-folder folder
@api \drive/folders/update do
folder_id: folder
parent_id: if @folder? then @folder.id else null
.then ~>
# something
.catch (err, text-status) ~>
console.error err
return false
</script>
</mk-drive-browser-nav-folder>

View File

@ -1,34 +1,41 @@
mk-ellipsis-icon
div
div
div
<mk-ellipsis-icon>
<div></div>
<div></div>
<div></div>
<style type="stylus">
:scope
display block
width 70px
margin 0 auto
text-align center
style.
display block
width 70px
margin 0 auto
text-align center
> div
display inline-block
width 18px
height 18px
background-color rgba(0, 0, 0, 0.3)
border-radius 100%
animation bounce 1.4s infinite ease-in-out both
> div
display inline-block
width 18px
height 18px
background-color rgba(0, 0, 0, 0.3)
border-radius 100%
animation bounce 1.4s infinite ease-in-out both
&:nth-child(1)
animation-delay 0s
&:nth-child(1)
animation-delay 0s
&:nth-child(2)
margin 0 6px
animation-delay 0.16s
&:nth-child(2)
margin 0 6px
animation-delay 0.16s
&:nth-child(3)
animation-delay 0.32s
&:nth-child(3)
animation-delay 0.32s
@keyframes bounce
0%, 80%, 100%
transform scale(0)
40%
transform scale(1)
@keyframes bounce
0%, 80%, 100%
transform scale(0)
40%
transform scale(1)
</style>
</mk-ellipsis-icon>

View File

@ -1,127 +1,124 @@
mk-follow-button
button(if={ !init }, class={ wait: wait, follow: !user.is_following, unfollow: user.is_following },
onclick={ onclick },
disabled={ wait },
title={ user.is_following ? 'フォロー解除' : 'フォローする' })
i.fa.fa-minus(if={ !wait && user.is_following })
i.fa.fa-plus(if={ !wait && !user.is_following })
i.fa.fa-spinner.fa-pulse.fa-fw(if={ wait })
div.init(if={ init }): i.fa.fa-spinner.fa-pulse.fa-fw
<mk-follow-button>
<button class="{ wait: wait, follow: !user.is_following, unfollow: user.is_following }" if="{ !init }" onclick="{ onclick }" disabled="{ wait }" title="{ user.is_following ? 'フォロー解除' : 'フォローする' }"><i class="fa fa-minus" if="{ !wait &amp;&amp; user.is_following }"></i><i class="fa fa-plus" if="{ !wait &amp;&amp; !user.is_following }"></i><i class="fa fa-spinner fa-pulse fa-fw" if="{ wait }"></i></button>
<div class="init" if="{ init }"><i class="fa fa-spinner fa-pulse fa-fw"></i></div>
<style type="stylus">
:scope
display block
style.
display block
> button
> .init
display block
cursor pointer
padding 0
margin 0
width 32px
height 32px
font-size 1em
outline none
border-radius 4px
> button
> .init
display block
cursor pointer
padding 0
margin 0
width 32px
height 32px
font-size 1em
outline none
border-radius 4px
*
pointer-events none
*
pointer-events none
&: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
&: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
&.follow
color #888
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
border solid 1px #e2e2e2
&.follow
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
&:hover
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
border-color #dcdcdc
&:active
background #ececec
border-color #dcdcdc
&:active
background #ececec
border-color #dcdcdc
&.unfollow
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%)
&.unfollow
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
&: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
&: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
&:active:not(:disabled)
background $theme-color
border-color $theme-color
&.wait
cursor wait !important
opacity 0.7
&.wait
cursor wait !important
opacity 0.7
</style>
<script>
@mixin \api
@mixin \is-promise
@mixin \stream
script.
@mixin \api
@mixin \is-promise
@mixin \stream
@user = null
@user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user
@init = true
@wait = false
@user = null
@user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user
@init = true
@wait = false
@on \mount ~>
@user-promise.then (user) ~>
@user = user
@init = false
@update!
@stream.on \follow @on-stream-follow
@stream.on \unfollow @on-stream-unfollow
@on \unmount ~>
@stream.off \follow @on-stream-follow
@stream.off \unfollow @on-stream-unfollow
@on-stream-follow = (user) ~>
if user.id == @user.id
@user = user
@update!
@on-stream-unfollow = (user) ~>
if user.id == @user.id
@user = user
@update!
@onclick = ~>
@wait = true
if @user.is_following
@api \following/delete do
user_id: @user.id
.then ~>
@user.is_following = false
.catch (err) ->
console.error err
.then ~>
@wait = false
@on \mount ~>
@user-promise.then (user) ~>
@user = user
@init = false
@update!
else
@api \following/create do
user_id: @user.id
.then ~>
@user.is_following = true
.catch (err) ->
console.error err
.then ~>
@wait = false
@stream.on \follow @on-stream-follow
@stream.on \unfollow @on-stream-unfollow
@on \unmount ~>
@stream.off \follow @on-stream-follow
@stream.off \unfollow @on-stream-unfollow
@on-stream-follow = (user) ~>
if user.id == @user.id
@user = user
@update!
@on-stream-unfollow = (user) ~>
if user.id == @user.id
@user = user
@update!
@onclick = ~>
@wait = true
if @user.is_following
@api \following/delete do
user_id: @user.id
.then ~>
@user.is_following = false
.catch (err) ->
console.error err
.then ~>
@wait = false
@update!
else
@api \following/create do
user_id: @user.id
.then ~>
@user.is_following = true
.catch (err) ->
console.error err
.then ~>
@wait = false
@update!
</script>
</mk-follow-button>

View File

@ -1,163 +1,163 @@
mk-following-setuper
p.title 気になるユーザーをフォロー:
div.users(if={ !loading && users.length > 0 })
div.user(each={ users })
a.avatar-anchor(href={ CONFIG.url + '/' + username })
img.avatar(src={ avatar_url + '?thumbnail&size=42' }, alt='', data-user-preview={ id })
div.body
a.name(href={ CONFIG.url + '/' + username }, target='_blank', data-user-preview={ id }) { name }
p.username @{ username }
mk-follow-button(user={ this })
p.empty(if={ !loading && users.length == 0 })
| おすすめのユーザーは見つかりませんでした。
p.loading(if={ loading })
i.fa.fa-spinner.fa-pulse.fa-fw
| 読み込んでいます
mk-ellipsis
a.refresh(onclick={ refresh }) もっと見る
button.close(onclick={ close }, title='閉じる'): i.fa.fa-times
style.
display block
padding 24px
background #fff
> .title
margin 0 0 12px 0
font-size 1em
font-weight bold
color #888
> .users
&:after
content ""
<mk-following-setuper>
<p class="title">気になるユーザーをフォロー:</p>
<div class="users" if="{ !loading &amp;&amp; users.length &gt; 0 }">
<div class="user" each="{ users }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + username }"><img class="avatar" src="{ avatar_url + '?thumbnail&amp;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>
<p class="username">@{ username }</p>
</div>
<mk-follow-button user="{ this }"></mk-follow-button>
</div>
</div>
<p class="empty" if="{ !loading &amp;&amp; users.length == 0 }">おすすめのユーザーは見つかりませんでした。</p>
<p class="loading" if="{ loading }"><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます
<mk-ellipsis></mk-ellipsis>
</p><a class="refresh" onclick="{ refresh }">もっと見る</a>
<button class="close" onclick="{ close }" title="閉じる"><i class="fa fa-times"></i></button>
<style type="stylus">
:scope
display block
clear both
padding 24px
background #fff
> .user
padding 16px
width 238px
float left
> .title
margin 0 0 12px 0
font-size 1em
font-weight bold
color #888
&:after
content ""
display block
clear both
> .avatar-anchor
display block
float left
margin 0 12px 0 0
> .avatar
> .users
&:after
content ""
display block
width 42px
height 42px
margin 0
border-radius 8px
vertical-align bottom
clear both
> .body
float left
width calc(100% - 54px)
> .user
padding 16px
width 238px
float left
> .name
margin 0
font-size 16px
line-height 24px
&:after
content ""
display block
clear both
> .avatar-anchor
display block
float left
margin 0 12px 0 0
> .avatar
display block
width 42px
height 42px
margin 0
border-radius 8px
vertical-align bottom
> .body
float left
width calc(100% - 54px)
> .name
margin 0
font-size 16px
line-height 24px
color #555
> .username
margin 0
font-size 15px
line-height 16px
color #ccc
> mk-follow-button
position absolute
top 16px
right 16px
> .empty
margin 0
padding 16px
text-align center
color #aaa
> .loading
margin 0
padding 16px
text-align center
color #aaa
> i
margin-right 4px
> .refresh
display block
margin 0 8px 0 0
text-align right
font-size 0.9em
color #999
> .close
cursor pointer
display block
position absolute
top 6px
right 6px
z-index 1
margin 0
padding 0
font-size 1.2em
color #999
border none
outline none
background transparent
&:hover
color #555
> .username
margin 0
font-size 15px
line-height 16px
color #ccc
&:active
color #222
> mk-follow-button
position absolute
top 16px
right 16px
> i
padding 14px
> .empty
margin 0
padding 16px
text-align center
color #aaa
</style>
<script>
@mixin \api
@mixin \user-preview
> .loading
margin 0
padding 16px
text-align center
color #aaa
> i
margin-right 4px
> .refresh
display block
margin 0 8px 0 0
text-align right
font-size 0.9em
color #999
> .close
cursor pointer
display block
position absolute
top 6px
right 6px
z-index 1
margin 0
padding 0
font-size 1.2em
color #999
border none
outline none
background transparent
&:hover
color #555
&:active
color #222
> i
padding 14px
script.
@mixin \api
@mixin \user-preview
@users = null
@loading = true
@limit = 6users
@page = 0
@on \mount ~>
@load!
@load = ~>
@loading = true
@users = null
@update!
@loading = true
@api \users/recommendation do
limit: @limit
offset: @limit * @page
.then (users) ~>
@loading = false
@users = users
@limit = 6users
@page = 0
@on \mount ~>
@load!
@load = ~>
@loading = true
@users = null
@update!
.catch (err, text-status) ->
console.error err
@refresh = ~>
if @users.length < @limit
@page = 0
else
@page++
@load!
@api \users/recommendation do
limit: @limit
offset: @limit * @page
.then (users) ~>
@loading = false
@users = users
@update!
.catch (err, text-status) ->
console.error err
@close = ~>
@unmount!
@refresh = ~>
if @users.length < @limit
@page = 0
else
@page++
@load!
@close = ~>
@unmount!
</script>
</mk-following-setuper>

View File

@ -1,15 +1,14 @@
mk-go-top
button.hidden(title='一番上へ')
i.fa.fa-angle-up
<mk-go-top>
<button class="hidden" title="一番上へ"><i class="fa fa-angle-up"></i></button>
<script>
window.add-event-listener \load @on-scroll
window.add-event-listener \scroll @on-scroll
window.add-event-listener \resize @on-scroll
script.
window.add-event-listener \load @on-scroll
window.add-event-listener \scroll @on-scroll
window.add-event-listener \resize @on-scroll
@on-scroll = ~>
if $ window .scroll-top! > 500px
@remove-class \hidden
else
@add-class \hidden
@on-scroll = ~>
if $ window .scroll-top! > 500px
@remove-class \hidden
else
@add-class \hidden
</script>
</mk-go-top>

View File

@ -1,75 +1,83 @@
mk-broadcast-home-widget
div.icon
svg(height='32', version='1.1', viewBox='0 0 32 32', width='32')
path.tower(d='M16.04,11.24c1.79,0,3.239-1.45,3.239-3.24S17.83,4.76,16.04,4.76c-1.79,0-3.24,1.45-3.24,3.24 C12.78,9.78,14.24,11.24,16.04,11.24z M16.04,13.84c-0.82,0-1.66-0.2-2.4-0.6L7.34,29.98h2.98l1.72-2h8l1.681,2H24.7L18.42,13.24 C17.66,13.64,16.859,13.84,16.04,13.84z M16.02,14.8l2.02,7.2h-4L16.02,14.8z M12.04,25.98l2-2h4l2,2H12.04z')
path.wave.a(d='M4.66,1.04c-0.508-0.508-1.332-0.508-1.84,0c-1.86,1.92-2.8,4.44-2.8,6.94c0,2.52,0.94,5.04,2.8,6.96 c0.5,0.52,1.32,0.52,1.82,0s0.5-1.36,0-1.88C3.28,11.66,2.6,9.82,2.6,7.98S3.28,4.3,4.64,2.9C5.157,2.391,5.166,1.56,4.66,1.04z')
path.wave.b(d='M9.58,12.22c0.5-0.5,0.5-1.34,0-1.84C8.94,9.72,8.62,8.86,8.62,8s0.32-1.72,0.96-2.38c0.5-0.52,0.5-1.34,0-1.84 C9.346,3.534,9.02,3.396,8.68,3.4c-0.32,0-0.66,0.12-0.9,0.38C6.64,4.94,6.08,6.48,6.08,8s0.58,3.06,1.7,4.22 C8.28,12.72,9.1,12.72,9.58,12.22z')
path.wave.c(d='M22.42,3.78c-0.5,0.5-0.5,1.34,0,1.84c0.641,0.66,0.96,1.52,0.96,2.38s-0.319,1.72-0.96,2.38c-0.5,0.52-0.5,1.34,0,1.84 c0.487,0.497,1.285,0.505,1.781,0.018c0.007-0.006,0.013-0.012,0.02-0.018c1.139-1.16,1.699-2.7,1.699-4.22s-0.561-3.06-1.699-4.22 c-0.494-0.497-1.297-0.5-1.794-0.007C22.424,3.775,22.422,3.778,22.42,3.78z')
path.wave.d(d='M29.18,1.06c-0.479-0.502-1.273-0.522-1.775-0.044c-0.016,0.015-0.029,0.029-0.045,0.044c-0.5,0.52-0.5,1.36,0,1.88 c1.361,1.4,2.041,3.24,2.041,5.08s-0.68,3.66-2.041,5.08c-0.5,0.52-0.5,1.36,0,1.88c0.509,0.508,1.332,0.508,1.841,0 c1.86-1.92,2.8-4.44,2.8-6.96C31.99,5.424,30.98,2.931,29.18,1.06z')
<mk-broadcast-home-widget>
<div class="icon">
<svg height="32" version="1.1" viewBox="0 0 32 32" width="32">
<path class="tower" d="M16.04,11.24c1.79,0,3.239-1.45,3.239-3.24S17.83,4.76,16.04,4.76c-1.79,0-3.24,1.45-3.24,3.24 C12.78,9.78,14.24,11.24,16.04,11.24z M16.04,13.84c-0.82,0-1.66-0.2-2.4-0.6L7.34,29.98h2.98l1.72-2h8l1.681,2H24.7L18.42,13.24 C17.66,13.64,16.859,13.84,16.04,13.84z M16.02,14.8l2.02,7.2h-4L16.02,14.8z M12.04,25.98l2-2h4l2,2H12.04z"></path>
<path class="wave a" d="M4.66,1.04c-0.508-0.508-1.332-0.508-1.84,0c-1.86,1.92-2.8,4.44-2.8,6.94c0,2.52,0.94,5.04,2.8,6.96 c0.5,0.52,1.32,0.52,1.82,0s0.5-1.36,0-1.88C3.28,11.66,2.6,9.82,2.6,7.98S3.28,4.3,4.64,2.9C5.157,2.391,5.166,1.56,4.66,1.04z"></path>
<path class="wave b" d="M9.58,12.22c0.5-0.5,0.5-1.34,0-1.84C8.94,9.72,8.62,8.86,8.62,8s0.32-1.72,0.96-2.38c0.5-0.52,0.5-1.34,0-1.84 C9.346,3.534,9.02,3.396,8.68,3.4c-0.32,0-0.66,0.12-0.9,0.38C6.64,4.94,6.08,6.48,6.08,8s0.58,3.06,1.7,4.22 C8.28,12.72,9.1,12.72,9.58,12.22z"></path>
<path class="wave c" d="M22.42,3.78c-0.5,0.5-0.5,1.34,0,1.84c0.641,0.66,0.96,1.52,0.96,2.38s-0.319,1.72-0.96,2.38c-0.5,0.52-0.5,1.34,0,1.84 c0.487,0.497,1.285,0.505,1.781,0.018c0.007-0.006,0.013-0.012,0.02-0.018c1.139-1.16,1.699-2.7,1.699-4.22s-0.561-3.06-1.699-4.22 c-0.494-0.497-1.297-0.5-1.794-0.007C22.424,3.775,22.422,3.778,22.42,3.78z"></path>
<path class="wave d" d="M29.18,1.06c-0.479-0.502-1.273-0.522-1.775-0.044c-0.016,0.015-0.029,0.029-0.045,0.044c-0.5,0.52-0.5,1.36,0,1.88 c1.361,1.4,2.041,3.24,2.041,5.08s-0.68,3.66-2.041,5.08c-0.5,0.52-0.5,1.36,0,1.88c0.509,0.508,1.332,0.508,1.841,0 c1.86-1.92,2.8-4.44,2.8-6.96C31.99,5.424,30.98,2.931,29.18,1.06z"></path>
</svg>
</div>
<h1>開発者募集中!</h1>
<p><a href="https://github.com/syuilo/misskey" target="_blank">Misskeyはオープンソースで開発されています。リポジトリはこちら。</a></p>
<style type="stylus">
:scope
display block
padding 10px 10px 10px 50px
background transparent
border-color #4078c0 !important
h1 開発者募集中!
p: a(href='https://github.com/syuilo/misskey', target='_blank') Misskeyはオープンソースで開発されています。リポジトリはこちら。
&:after
content ""
display block
clear both
style.
display block
padding 10px 10px 10px 50px
background transparent
border-color #4078c0 !important
> .icon
display block
float left
margin-left -40px
&:after
content ""
display block
clear both
> svg
fill currentColor
color #4078c0
> .icon
display block
float left
margin-left -40px
> .wave
opacity 1
&.a
animation wave 20s ease-in-out 2.1s infinite
&.b
animation wave 20s ease-in-out 2s infinite
&.c
animation wave 20s ease-in-out 2s infinite
&.d
animation wave 20s ease-in-out 2.1s infinite
@keyframes wave
0%
opacity 1
1.5%
opacity 0
3.5%
opacity 0
5%
opacity 1
6.5%
opacity 0
8.5%
opacity 0
10%
opacity 1
> h1
margin 0
font-size 0.95em
font-weight normal
color #4078c0
> p
display block
z-index 1
margin 0
font-size 0.7em
color #555
a
color #555
> svg
fill currentColor
color #4078c0
> .wave
opacity 1
&.a
animation wave 20s ease-in-out 2.1s infinite
&.b
animation wave 20s ease-in-out 2s infinite
&.c
animation wave 20s ease-in-out 2s infinite
&.d
animation wave 20s ease-in-out 2.1s infinite
@keyframes wave
0%
opacity 1
1.5%
opacity 0
3.5%
opacity 0
5%
opacity 1
6.5%
opacity 0
8.5%
opacity 0
10%
opacity 1
> h1
margin 0
font-size 0.95em
font-weight normal
color #4078c0
> p
display block
z-index 1
margin 0
font-size 0.7em
color #555
a
color #555
</style>
</mk-broadcast-home-widget>

View File

@ -1,147 +1,148 @@
mk-calendar-home-widget(data-special={ special })
div.calendar(data-is-holiday={ is-holiday })
p.month-and-year
span.year { year }年
span.month { month }月
p.day { day }日
p.week-day { week-day }曜日
div.info
div
p
| 今日:
b { day-p.to-fixed(1) }%
div.meter
div.val(style={ 'width:' + day-p + '%' })
<mk-calendar-home-widget data-special="{ special }">
<div class="calendar" data-is-holiday="{ isHoliday }">
<p class="month-and-year"><span class="year">{ year }年</span><span class="month">{ month }月</span></p>
<p class="day">{ day }日</p>
<p class="week-day">{ weekDay }曜日</p>
</div>
<div class="info">
<div>
<p>今日:<b>{ dayP.toFixed(1) }%</b></p>
<div class="meter">
<div class="val" style="{ 'width:' + dayP + '%' }"></div>
</div>
</div>
<div>
<p>今月:<b>{ monthP.toFixed(1) }%</b></p>
<div class="meter">
<div class="val" style="{ 'width:' + monthP + '%' }"></div>
</div>
</div>
<div>
<p>今年:<b>{ yearP.toFixed(1) }%</b></p>
<div class="meter">
<div class="val" style="{ 'width:' + yearP + '%' }"></div>
</div>
</div>
</div>
<style type="stylus">
:scope
display block
padding 16px 0
color #777
background #fff
div
p
| 今月:
b { month-p.to-fixed(1) }%
div.meter
div.val(style={ 'width:' + month-p + '%' })
&[data-special='on-new-years-day']
border-color #ef95a0 !important
div
p
| 今年:
b { year-p.to-fixed(1) }%
div.meter
div.val(style={ 'width:' + year-p + '%' })
&:after
content ""
display block
clear both
style.
display block
padding 16px 0
color #777
background #fff
> .calendar
float left
width 60%
text-align center
&[data-special='on-new-years-day']
border-color #ef95a0 !important
&[data-is-holiday]
> .day
color #ef95a0
&:after
content ""
display block
clear both
> p
margin 0
line-height 18px
font-size 14px
> .calendar
float left
width 60%
text-align center
> span
margin 0 4px
&[data-is-holiday]
> .day
color #ef95a0
> .day
margin 10px 0
line-height 32px
font-size 28px
> p
margin 0
line-height 18px
font-size 14px
> .info
display block
float left
width 40%
padding 0 16px 0 0
> span
margin 0 4px
> div
margin-bottom 8px
> .day
margin 10px 0
line-height 32px
font-size 28px
&:last-child
margin-bottom 4px
> .info
display block
float left
width 40%
padding 0 16px 0 0
> p
margin 0 0 2px 0
font-size 12px
line-height 18px
color #888
> div
margin-bottom 8px
> b
margin-left 2px
&:last-child
margin-bottom 4px
> .meter
width 100%
overflow hidden
background #eee
border-radius 8px
> p
margin 0 0 2px 0
font-size 12px
line-height 18px
color #888
> .val
height 4px
background $theme-color
> b
margin-left 2px
&:nth-child(1)
> .meter > .val
background #f7796c
> .meter
width 100%
overflow hidden
background #eee
border-radius 8px
&:nth-child(2)
> .meter > .val
background #a1de41
> .val
height 4px
background $theme-color
&:nth-child(3)
> .meter > .val
background #41ddde
&:nth-child(1)
> .meter > .val
background #f7796c
</style>
<script>
@draw = ~>
now = new Date!
nd = now.get-date!
nm = now.get-month!
ny = now.get-full-year!
&:nth-child(2)
> .meter > .val
background #a1de41
@year = ny
@month = nm + 1
@day = nd
@week-day = [\日 \月 \火 \水 \木 \金 \土][now.get-day!]
&:nth-child(3)
> .meter > .val
background #41ddde
@day-numer = (now - (new Date ny, nm, nd))
@day-denom = 1000ms * 60s * 60m * 24h
@month-numer = (now - (new Date ny, nm, 1))
@month-denom = (new Date ny, nm + 1, 1) - (new Date ny, nm, 1)
@year-numer = (now - (new Date ny, 0, 1))
@year-denom = (new Date ny + 1, 0, 1) - (new Date ny, 0, 1)
script.
@draw = ~>
now = new Date!
nd = now.get-date!
nm = now.get-month!
ny = now.get-full-year!
@day-p = @day-numer / @day-denom * 100
@month-p = @month-numer / @month-denom * 100
@year-p = @year-numer / @year-denom * 100
@year = ny
@month = nm + 1
@day = nd
@week-day = [\日 \月 \火 \水 \木 \金 \土][now.get-day!]
@is-holiday =
(now.get-day! == 0 or now.get-day! == 6)
@day-numer = (now - (new Date ny, nm, nd))
@day-denom = 1000ms * 60s * 60m * 24h
@month-numer = (now - (new Date ny, nm, 1))
@month-denom = (new Date ny, nm + 1, 1) - (new Date ny, nm, 1)
@year-numer = (now - (new Date ny, 0, 1))
@year-denom = (new Date ny + 1, 0, 1) - (new Date ny, 0, 1)
@special =
| nm == 0 and nd == 1 => \on-new-years-day
| _ => false
@day-p = @day-numer / @day-denom * 100
@month-p = @month-numer / @month-denom * 100
@year-p = @year-numer / @year-denom * 100
@update!
@is-holiday =
(now.get-day! == 0 or now.get-day! == 6)
@draw!
@special =
| nm == 0 and nd == 1 => \on-new-years-day
| _ => false
@on \mount ~>
@clock = set-interval @draw, 1000ms
@update!
@draw!
@on \mount ~>
@clock = set-interval @draw, 1000ms
@on \unmount ~>
clear-interval @clock
@on \unmount ~>
clear-interval @clock
</script>
</mk-calendar-home-widget>

View File

@ -1,37 +1,36 @@
mk-donation-home-widget
article
h1
i.fa.fa-heart
| 寄付のお願い
p
| Misskeyの運営にはドメイン、サーバー等のコストが掛かります。
| Misskeyは広告を掲載したりしないため、 収入を皆様からの寄付に頼っています。
| もしご興味があれば、
a(href='/syuilo', data-user-preview='@syuilo') @syuilo
| までご連絡ください。ご協力ありがとうございます。
style.
display block
background #fff
border-color #ead8bb !important
> article
padding 20px
> h1
margin 0 0 5px 0
font-size 1em
color #888
> i
margin-right 0.25em
> p
<mk-donation-home-widget>
<article>
<h1><i class="fa fa-heart"></i>寄付のお願い</h1>
<p>
Misskeyの運営にはドメイン、サーバー等のコストが掛かります。
Misskeyは広告を掲載したりしないため、 収入を皆様からの寄付に頼っています。
もしご興味があれば、<a href="/syuilo" data-user-preview="@syuilo">@syuilo</a>までご連絡ください。ご協力ありがとうございます。
</p>
</article>
<style type="stylus">
:scope
display block
z-index 1
margin 0
font-size 0.8em
color #999
background #fff
border-color #ead8bb !important
script.
@mixin \user-preview
> article
padding 20px
> h1
margin 0 0 5px 0
font-size 1em
color #888
> i
margin-right 0.25em
> p
display block
z-index 1
margin 0
font-size 0.8em
color #999
</style>
<script>@mixin \user-preview</script>
</mk-donation-home-widget>

View File

@ -1,117 +1,112 @@
mk-mentions-home-widget
header
span(data-is-active={ mode == 'all' }, onclick={ set-mode.bind(this, 'all') }) すべて
span(data-is-active={ mode == 'following' }, onclick={ set-mode.bind(this, 'following') }) フォロー中
div.loading(if={ is-loading })
mk-ellipsis-icon
p.empty(if={ is-empty })
i.fa.fa-comments-o
span(if={ mode == 'all' }) あなた宛ての投稿はありません。
span(if={ mode == 'following' }) あなたがフォローしているユーザーからの言及はありません。
mk-timeline@timeline
<yield to="footer">
i.fa.fa-moon-o(if={ !parent.more-loading })
i.fa.fa-spinner.fa-pulse.fa-fw(if={ parent.more-loading })
</yield>
style.
display block
background #fff
> header
padding 8px 16px
border-bottom solid 1px #eee
> span
margin-right 16px
line-height 27px
font-size 18px
color #555
&:not([data-is-active])
color $theme-color
cursor pointer
&:hover
text-decoration underline
> .loading
padding 64px 0
> .empty
display block
margin 0 auto
padding 32px
max-width 400px
text-align center
color #999
> i
<mk-mentions-home-widget>
<header><span data-is-active="{ mode == 'all' }" onclick="{ setMode.bind(this, 'all') }">すべて</span><span data-is-active="{ mode == 'following' }" onclick="{ setMode.bind(this, 'following') }">フォロー中</span></header>
<div class="loading" if="{ isLoading }">
<mk-ellipsis-icon></mk-ellipsis-icon>
</div>
<p class="empty" if="{ isEmpty }"><i class="fa fa-comments-o"></i><span if="{ mode == 'all' }">あなた宛ての投稿はありません。</span><span if="{ mode == 'following' }">あなたがフォローしているユーザーからの言及はありません。</span></p>
<mk-timeline ref="timeline"><yield to="footer"><i class="fa fa-moon-o" if="{ !parent.moreLoading }"></i><i class="fa fa-spinner fa-pulse fa-fw" if="{ parent.moreLoading }"></i></yield></mk-timeline>
<style type="stylus">
:scope
display block
margin-bottom 16px
font-size 3em
color #ccc
background #fff
script.
@mixin \i
@mixin \api
> header
padding 8px 16px
border-bottom solid 1px #eee
@is-loading = true
@is-empty = false
@more-loading = false
@mode = \all
> span
margin-right 16px
line-height 27px
font-size 18px
color #555
@on \mount ~>
document.add-event-listener \keydown @on-document-keydown
window.add-event-listener \scroll @on-scroll
&:not([data-is-active])
color $theme-color
cursor pointer
@fetch ~>
@trigger \loaded
&:hover
text-decoration underline
@on \unmount ~>
document.remove-event-listener \keydown @on-document-keydown
window.remove-event-listener \scroll @on-scroll
> .loading
padding 64px 0
@on-document-keydown = (e) ~>
tag = e.target.tag-name.to-lower-case!
if tag != \input and tag != \textarea
if e.which == 84 # t
@refs.timeline.focus!
> .empty
display block
margin 0 auto
padding 32px
max-width 400px
text-align center
color #999
@fetch = (cb) ~>
@api \posts/mentions do
following: @mode == \following
.then (posts) ~>
@is-loading = false
@is-empty = posts.length == 0
> i
display block
margin-bottom 16px
font-size 3em
color #ccc
</style>
<script>
@mixin \i
@mixin \api
@is-loading = true
@is-empty = false
@more-loading = false
@mode = \all
@on \mount ~>
document.add-event-listener \keydown @on-document-keydown
window.add-event-listener \scroll @on-scroll
@fetch ~>
@trigger \loaded
@on \unmount ~>
document.remove-event-listener \keydown @on-document-keydown
window.remove-event-listener \scroll @on-scroll
@on-document-keydown = (e) ~>
tag = e.target.tag-name.to-lower-case!
if tag != \input and tag != \textarea
if e.which == 84 # t
@refs.timeline.focus!
@fetch = (cb) ~>
@api \posts/mentions do
following: @mode == \following
.then (posts) ~>
@is-loading = false
@is-empty = posts.length == 0
@update!
@refs.timeline.set-posts posts
if cb? then cb!
.catch (err) ~>
console.error err
if cb? then cb!
@more = ~>
if @more-loading or @is-loading or @refs.timeline.posts.length == 0
return
@more-loading = true
@update!
@refs.timeline.set-posts posts
if cb? then cb!
.catch (err) ~>
console.error err
if cb? then cb!
@api \posts/mentions do
following: @mode == \following
max_id: @refs.timeline.tail!.id
.then (posts) ~>
@more-loading = false
@update!
@refs.timeline.prepend-posts posts
.catch (err) ~>
console.error err
@more = ~>
if @more-loading or @is-loading or @refs.timeline.posts.length == 0
return
@more-loading = true
@update!
@api \posts/mentions do
following: @mode == \following
max_id: @refs.timeline.tail!.id
.then (posts) ~>
@more-loading = false
@update!
@refs.timeline.prepend-posts posts
.catch (err) ~>
console.error err
@on-scroll = ~>
current = window.scroll-y + window.inner-height
if current > document.body.offset-height - 8
@more!
@on-scroll = ~>
current = window.scroll-y + window.inner-height
if current > document.body.offset-height - 8
@more!
@set-mode = (mode) ~>
@update do
mode: mode
@fetch!
@set-mode = (mode) ~>
@update do
mode: mode
@fetch!
</script>
</mk-mentions-home-widget>

View File

@ -1,23 +1,21 @@
mk-nav-home-widget
a(href={ CONFIG.urls.about }) Misskeyについて
i ・
a(href={ CONFIG.urls.about + '/status' }) ステータス
i ・
a(href='https://github.com/syuilo/misskey') リポジトリ
i ・
a(href={ CONFIG.urls.dev }) 開発者
i ・
a(href='https://twitter.com/misskey_xyz', target='_blank') Follow us on <i class="fa fa-twitter"></i>
<mk-nav-home-widget><a href="{ CONFIG.urls.about }">Misskeyについて</a><i>・</i><a href="{ CONFIG.urls.about + '/status' }">ステータス</a><i>・</i><a href="https://github.com/syuilo/misskey">リポジトリ</a><i>・</i><a href="{ CONFIG.urls.dev }">開発者</a><i>・</i><a href="https://twitter.com/misskey_xyz" target="_blank">Follow us on <i class="fa fa-twitter"></i></a>
<style type="stylus">
:scope
display block
padding 16px
font-size 12px
color #aaa
background #fff
style.
display block
padding 16px
font-size 12px
color #aaa
background #fff
a
color #999
a
color #999
i
color #ccc
i
color #ccc
</style>
</mk-nav-home-widget>

View File

@ -1,49 +1,50 @@
mk-notifications-home-widget
p.title
i.fa.fa-bell-o
| 通知
button(onclick={ settings }, title='通知の設定'): i.fa.fa-cog
mk-notifications
<mk-notifications-home-widget>
<p class="title"><i class="fa fa-bell-o"></i>通知</p>
<button onclick="{ settings }" title="通知の設定"><i class="fa fa-cog"></i></button>
<mk-notifications></mk-notifications>
<style type="stylus">
:scope
display block
background #fff
style.
display block
background #fff
> .title
z-index 1
margin 0
padding 0 16px
line-height 42px
font-size 0.9em
font-weight bold
color #888
box-shadow 0 1px rgba(0, 0, 0, 0.07)
> .title
z-index 1
margin 0
padding 0 16px
line-height 42px
font-size 0.9em
font-weight bold
color #888
box-shadow 0 1px rgba(0, 0, 0, 0.07)
> i
margin-right 4px
> i
margin-right 4px
> button
position absolute
z-index 2
top 0
right 0
padding 0
width 42px
font-size 0.9em
line-height 42px
color #ccc
> button
position absolute
z-index 2
top 0
right 0
padding 0
width 42px
font-size 0.9em
line-height 42px
color #ccc
&:hover
color #aaa
&:hover
color #aaa
&:active
color #999
&:active
color #999
> mk-notifications
max-height 300px
overflow auto
> mk-notifications
max-height 300px
overflow auto
script.
@settings = ~>
w = riot.mount document.body.append-child document.create-element \mk-settings-window .0
w.switch \notification
</style>
<script>
@settings = ~>
w = riot.mount document.body.append-child document.create-element \mk-settings-window .0
w.switch \notification
</script>
</mk-notifications-home-widget>

View File

@ -1,86 +1,87 @@
mk-photo-stream-home-widget
p.title
i.fa.fa-camera
| フォトストリーム
p.initializing(if={ initializing })
i.fa.fa-spinner.fa-pulse.fa-fw
| 読み込んでいます
mk-ellipsis
div.stream(if={ !initializing && images.length > 0 })
virtual(each={ image in images })
div.img(style={ 'background-image: url(' + image.url + '?thumbnail&size=256)' })
p.empty(if={ !initializing && images.length == 0 })
| 写真はありません
<mk-photo-stream-home-widget>
<p class="title"><i class="fa fa-camera"></i>フォトストリーム</p>
<p class="initializing" if="{ initializing }"><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます
<mk-ellipsis></mk-ellipsis>
</p>
<div class="stream" if="{ !initializing &amp;&amp; images.length &gt; 0 }">
<virtual each="{ image in images }">
<div class="img" style="{ 'background-image: url(' + image.url + '?thumbnail&amp;size=256)' }"></div>
</virtual>
</div>
<p class="empty" if="{ !initializing &amp;&amp; images.length == 0 }">写真はありません</p>
<style type="stylus">
:scope
display block
background #fff
style.
display block
background #fff
> .title
z-index 1
margin 0
padding 0 16px
line-height 42px
font-size 0.9em
font-weight bold
color #888
box-shadow 0 1px rgba(0, 0, 0, 0.07)
> .title
z-index 1
margin 0
padding 0 16px
line-height 42px
font-size 0.9em
font-weight bold
color #888
box-shadow 0 1px rgba(0, 0, 0, 0.07)
> i
margin-right 4px
> i
margin-right 4px
> .stream
display -webkit-flex
display -moz-flex
display -ms-flex
display flex
justify-content center
flex-wrap wrap
padding 8px
> .stream
display -webkit-flex
display -moz-flex
display -ms-flex
display flex
justify-content center
flex-wrap wrap
padding 8px
> .img
flex 1 1 33%
width 33%
height 80px
background-position center center
background-size cover
background-clip content-box
border solid 2px transparent
> .img
flex 1 1 33%
width 33%
height 80px
background-position center center
background-size cover
background-clip content-box
border solid 2px transparent
> .initializing
> .empty
margin 0
padding 16px
text-align center
color #aaa
> .initializing
> .empty
margin 0
padding 16px
text-align center
color #aaa
> i
margin-right 4px
> i
margin-right 4px
</style>
<script>
@mixin \api
@mixin \stream
script.
@mixin \api
@mixin \stream
@images = []
@initializing = true
@images = []
@initializing = true
@on \mount ~>
@stream.on \drive_file_created @on-stream-drive-file-created
@on \mount ~>
@stream.on \drive_file_created @on-stream-drive-file-created
@api \drive/stream do
type: 'image/*'
limit: 9images
.then (images) ~>
@initializing = false
@images = images
@update!
@api \drive/stream do
type: 'image/*'
limit: 9images
.then (images) ~>
@initializing = false
@images = images
@update!
@on \unmount ~>
@stream.off \drive_file_created @on-stream-drive-file-created
@on \unmount ~>
@stream.off \drive_file_created @on-stream-drive-file-created
@on-stream-drive-file-created = (file) ~>
if /^image\/.+$/.test file.type
@images.unshift file
if @images.length > 9
@images.pop!
@update!
@on-stream-drive-file-created = (file) ~>
if /^image\/.+$/.test file.type
@images.unshift file
if @images.length > 9
@images.pop!
@update!
</script>
</mk-photo-stream-home-widget>

View File

@ -1,55 +1,56 @@
mk-profile-home-widget
div.banner(style={ I.banner_url ? 'background-image: url(' + I.banner_url + '?thumbnail&size=256)' : '' }, onclick={ set-banner })
img.avatar(src={ I.avatar_url + '?thumbnail&size=64' }, onclick={ set-avatar }, alt='avatar', data-user-preview={ I.id })
a.name(href={ CONFIG.url + '/' + I.username }) { I.name }
p.username @{ I.username }
<mk-profile-home-widget>
<div class="banner" style="{ I.banner_url ? 'background-image: url(' + I.banner_url + '?thumbnail&amp;size=256)' : '' }" onclick="{ setBanner }"></div><img class="avatar" src="{ I.avatar_url + '?thumbnail&amp;size=64' }" onclick="{ setAvatar }" alt="avatar" data-user-preview="{ I.id }"/><a class="name" href="{ CONFIG.url + '/' + I.username }">{ I.name }</a>
<p class="username">@{ I.username }</p>
<style type="stylus">
:scope
display block
background #fff
style.
display block
background #fff
> .banner
height 100px
background-color #f5f5f5
background-size cover
background-position center
> .banner
height 100px
background-color #f5f5f5
background-size cover
background-position center
> .avatar
display block
position absolute
top 76px
left 16px
width 58px
height 58px
margin 0
border solid 3px #fff
border-radius 8px
vertical-align bottom
> .avatar
display block
position absolute
top 76px
left 16px
width 58px
height 58px
margin 0
border solid 3px #fff
border-radius 8px
vertical-align bottom
> .name
display block
margin 10px 0 0 92px
line-height 16px
font-weight bold
color #555
> .name
display block
margin 10px 0 0 92px
line-height 16px
font-weight bold
color #555
> .username
display block
margin 4px 0 8px 92px
line-height 16px
font-size 0.9em
color #999
> .username
display block
margin 4px 0 8px 92px
line-height 16px
font-size 0.9em
color #999
</style>
<script>
@mixin \i
@mixin \user-preview
@mixin \update-avatar
@mixin \update-banner
script.
@mixin \i
@mixin \user-preview
@mixin \update-avatar
@mixin \update-banner
@set-avatar = ~>
@update-avatar @I, (i) ~>
@update-i i
@set-avatar = ~>
@update-avatar @I, (i) ~>
@update-i i
@set-banner = ~>
@update-banner @I, (i) ~>
@update-i i
@set-banner = ~>
@update-banner @I, (i) ~>
@update-i i
</script>
</mk-profile-home-widget>

View File

@ -1,94 +1,94 @@
mk-rss-reader-home-widget
p.title
i.fa.fa-rss-square
| RSS
button(onclick={ settings }, title='設定'): i.fa.fa-cog
div.feed(if={ !initializing })
virtual(each={ item in items })
a(href={ item.link }, target='_blank') { item.title }
p.initializing(if={ initializing })
i.fa.fa-spinner.fa-pulse.fa-fw
| 読み込んでいます
mk-ellipsis
style.
display block
background #fff
> .title
margin 0
padding 0 16px
line-height 42px
font-size 0.9em
font-weight bold
color #888
box-shadow 0 1px rgba(0, 0, 0, 0.07)
> i
margin-right 4px
> button
position absolute
top 0
right 0
padding 0
width 42px
font-size 0.9em
line-height 42px
color #ccc
&:hover
color #aaa
&:active
color #999
> .feed
padding 12px 16px
font-size 0.9em
> a
<mk-rss-reader-home-widget>
<p class="title"><i class="fa fa-rss-square"></i>RSS</p>
<button onclick="{ settings }" title="設定"><i class="fa fa-cog"></i></button>
<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></mk-ellipsis>
</p>
<style type="stylus">
:scope
display block
padding 4px 0
color #666
border-bottom dashed 1px #eee
background #fff
&:last-child
border-bottom none
> .title
margin 0
padding 0 16px
line-height 42px
font-size 0.9em
font-weight bold
color #888
box-shadow 0 1px rgba(0, 0, 0, 0.07)
> .initializing
margin 0
padding 16px
text-align center
color #aaa
> i
margin-right 4px
> i
margin-right 4px
> button
position absolute
top 0
right 0
padding 0
width 42px
font-size 0.9em
line-height 42px
color #ccc
script.
@mixin \api
@mixin \NotImplementedException
&:hover
color #aaa
@url = 'http://news.yahoo.co.jp/pickup/rss.xml'
@items = []
@initializing = true
&:active
color #999
@on \mount ~>
@fetch!
@clock = set-interval @fetch, 60000ms
> .feed
padding 12px 16px
font-size 0.9em
@on \unmount ~>
clear-interval @clock
> a
display block
padding 4px 0
color #666
border-bottom dashed 1px #eee
@fetch = ~>
@api CONFIG.url + '/api:rss' do
url: @url
.then (feed) ~>
@items = feed.rss.channel.item
@initializing = false
@update!
.catch (err) ->
console.error err
&:last-child
border-bottom none
@settings = ~>
@NotImplementedException!
> .initializing
margin 0
padding 16px
text-align center
color #aaa
> i
margin-right 4px
</style>
<script>
@mixin \api
@mixin \NotImplementedException
@url = 'http://news.yahoo.co.jp/pickup/rss.xml'
@items = []
@initializing = true
@on \mount ~>
@fetch!
@clock = set-interval @fetch, 60000ms
@on \unmount ~>
clear-interval @clock
@fetch = ~>
@api CONFIG.url + '/api:rss' do
url: @url
.then (feed) ~>
@items = feed.rss.channel.item
@initializing = false
@update!
.catch (err) ->
console.error err
@settings = ~>
@NotImplementedException!
</script>
</mk-rss-reader-home-widget>

View File

@ -1,113 +1,111 @@
mk-timeline-home-widget
mk-following-setuper(if={ no-following })
div.loading(if={ is-loading })
mk-ellipsis-icon
p.empty(if={ is-empty })
i.fa.fa-comments-o
| 自分の投稿や、自分がフォローしているユーザーの投稿が表示されます。
mk-timeline@timeline
<yield to="footer">
i.fa.fa-moon-o(if={ !parent.more-loading })
i.fa.fa-spinner.fa-pulse.fa-fw(if={ parent.more-loading })
</yield>
style.
display block
background #fff
> mk-following-setuper
border-bottom solid 1px #eee
> .loading
padding 64px 0
> .empty
display block
margin 0 auto
padding 32px
max-width 400px
text-align center
color #999
> i
<mk-timeline-home-widget>
<mk-following-setuper if="{ noFollowing }"></mk-following-setuper>
<div class="loading" if="{ isLoading }">
<mk-ellipsis-icon></mk-ellipsis-icon>
</div>
<p class="empty" if="{ isEmpty }"><i class="fa fa-comments-o"></i>自分の投稿や、自分がフォローしているユーザーの投稿が表示されます。</p>
<mk-timeline ref="timeline"><yield to="footer"><i class="fa fa-moon-o" if="{ !parent.moreLoading }"></i><i class="fa fa-spinner fa-pulse fa-fw" if="{ parent.moreLoading }"></i></yield></mk-timeline>
<style type="stylus">
:scope
display block
margin-bottom 16px
font-size 3em
color #ccc
background #fff
script.
@mixin \i
@mixin \api
@mixin \stream
> mk-following-setuper
border-bottom solid 1px #eee
@is-loading = true
@is-empty = false
@more-loading = false
@no-following = @I.following_count == 0
> .loading
padding 64px 0
@on \mount ~>
@stream.on \post @on-stream-post
@stream.on \follow @on-stream-follow
@stream.on \unfollow @on-stream-unfollow
> .empty
display block
margin 0 auto
padding 32px
max-width 400px
text-align center
color #999
document.add-event-listener \keydown @on-document-keydown
window.add-event-listener \scroll @on-scroll
> i
display block
margin-bottom 16px
font-size 3em
color #ccc
@load ~>
@trigger \loaded
</style>
<script>
@mixin \i
@mixin \api
@mixin \stream
@on \unmount ~>
@stream.off \post @on-stream-post
@stream.off \follow @on-stream-follow
@stream.off \unfollow @on-stream-unfollow
document.remove-event-listener \keydown @on-document-keydown
window.remove-event-listener \scroll @on-scroll
@on-document-keydown = (e) ~>
tag = e.target.tag-name.to-lower-case!
if tag != \input and tag != \textarea
if e.which == 84 # t
@refs.timeline.focus!
@load = (cb) ~>
@api \posts/timeline
.then (posts) ~>
@is-loading = false
@is-empty = posts.length == 0
@update!
@refs.timeline.set-posts posts
if cb? then cb!
.catch (err) ~>
console.error err
if cb? then cb!
@more = ~>
if @more-loading or @is-loading or @refs.timeline.posts.length == 0
return
@more-loading = true
@update!
@api \posts/timeline do
max_id: @refs.timeline.tail!.id
.then (posts) ~>
@more-loading = false
@update!
@refs.timeline.prepend-posts posts
.catch (err) ~>
console.error err
@on-stream-post = (post) ~>
@is-loading = true
@is-empty = false
@update!
@refs.timeline.add-post post
@more-loading = false
@no-following = @I.following_count == 0
@on-stream-follow = ~>
@load!
@on \mount ~>
@stream.on \post @on-stream-post
@stream.on \follow @on-stream-follow
@stream.on \unfollow @on-stream-unfollow
@on-stream-unfollow = ~>
@load!
document.add-event-listener \keydown @on-document-keydown
window.add-event-listener \scroll @on-scroll
@on-scroll = ~>
current = window.scroll-y + window.inner-height
if current > document.body.offset-height - 8
@more!
@load ~>
@trigger \loaded
@on \unmount ~>
@stream.off \post @on-stream-post
@stream.off \follow @on-stream-follow
@stream.off \unfollow @on-stream-unfollow
document.remove-event-listener \keydown @on-document-keydown
window.remove-event-listener \scroll @on-scroll
@on-document-keydown = (e) ~>
tag = e.target.tag-name.to-lower-case!
if tag != \input and tag != \textarea
if e.which == 84 # t
@refs.timeline.focus!
@load = (cb) ~>
@api \posts/timeline
.then (posts) ~>
@is-loading = false
@is-empty = posts.length == 0
@update!
@refs.timeline.set-posts posts
if cb? then cb!
.catch (err) ~>
console.error err
if cb? then cb!
@more = ~>
if @more-loading or @is-loading or @refs.timeline.posts.length == 0
return
@more-loading = true
@update!
@api \posts/timeline do
max_id: @refs.timeline.tail!.id
.then (posts) ~>
@more-loading = false
@update!
@refs.timeline.prepend-posts posts
.catch (err) ~>
console.error err
@on-stream-post = (post) ~>
@is-empty = false
@update!
@refs.timeline.add-post post
@on-stream-follow = ~>
@load!
@on-stream-unfollow = ~>
@load!
@on-scroll = ~>
current = window.scroll-y + window.inner-height
if current > document.body.offset-height - 8
@more!
</script>
</mk-timeline-home-widget>

View File

@ -1,70 +1,71 @@
mk-tips-home-widget
p@tip
i.fa.fa-lightbulb-o
span@text
<mk-tips-home-widget>
<p ref="tip"><i class="fa fa-lightbulb-o"></i><span ref="text"></span></p>
<style type="stylus">
:scope
display block
background transparent !important
border none !important
overflow visible !important
style.
display block
background transparent !important
border none !important
overflow visible !important
> p
display block
margin 0
padding 0 12px
text-align center
font-size 0.7em
color #999
> p
display block
margin 0
padding 0 12px
text-align center
font-size 0.7em
color #999
> i
margin-right 4px
> i
margin-right 4px
kbd
display inline
padding 0 6px
margin 0 2px
font-size 1em
font-family inherit
border solid 1px #999
border-radius 2px
kbd
display inline
padding 0 6px
margin 0 2px
font-size 1em
font-family inherit
border solid 1px #999
border-radius 2px
</style>
<script>
@tips = [
'<kbd>t</kbd>でタイムラインにフォーカスできます'
'<kbd>p</kbd>または<kbd>n</kbd>で投稿フォームを開きます'
'投稿フォームにはファイルをドラッグ&ドロップできます'
'投稿フォームにクリップボードにある画像データをペーストできます'
'ドライブにファイルをドラッグ&ドロップしてアップロードできます'
'ドライブでファイルをドラッグしてフォルダ移動できます'
'ドライブでフォルダをドラッグしてフォルダ移動できます'
'ホームをカスタマイズできます(準備中)'
'MisskeyはMIT Licenseです'
]
script.
@tips = [
'<kbd>t</kbd>でタイムラインにフォーカスできます'
'<kbd>p</kbd>または<kbd>n</kbd>で投稿フォームを開きます'
'投稿フォームにはファイルをドラッグ&ドロップできます'
'投稿フォームにクリップボードにある画像データをペーストできます'
'ドライブにファイルをドラッグ&ドロップしてアップロードできます'
'ドライブでファイルをドラッグしてフォルダ移動できます'
'ドライブでフォルダをドラッグしてフォルダ移動できます'
'ホームをカスタマイズできます(準備中)'
'MisskeyはMIT Licenseです'
]
@on \mount ~>
@set!
@clock = set-interval @change, 20000ms
@on \mount ~>
@set!
@clock = set-interval @change, 20000ms
@on \unmount ~>
clear-interval @clock
@on \unmount ~>
clear-interval @clock
@set = ~>
@refs.text.innerHTML = @tips[Math.floor Math.random! * @tips.length]
@update!
@set = ~>
@refs.text.innerHTML = @tips[Math.floor Math.random! * @tips.length]
@update!
@change = ~>
Velocity @refs.tip, {
opacity: 0
} {
duration: 500ms
easing: \linear
complete: @set
}
@change = ~>
Velocity @refs.tip, {
opacity: 0
} {
duration: 500ms
easing: \linear
complete: @set
}
Velocity @refs.tip, {
opacity: 1
} {
duration: 500ms
easing: \linear
}
Velocity @refs.tip, {
opacity: 1
} {
duration: 500ms
easing: \linear
}
</script>
</mk-tips-home-widget>

View File

@ -1,154 +1,152 @@
mk-user-recommendation-home-widget
p.title
i.fa.fa-users
| おすすめユーザー
button(onclick={ refresh }, title='他を見る'): i.fa.fa-refresh
div.user(if={ !loading && users.length != 0 }, each={ _user in users })
a.avatar-anchor(href={ CONFIG.url + '/' + _user.username })
img.avatar(src={ _user.avatar_url + '?thumbnail&size=42' }, alt='', data-user-preview={ _user.id })
div.body
a.name(href={ CONFIG.url + '/' + _user.username }, data-user-preview={ _user.id }) { _user.name }
p.username @{ _user.username }
mk-follow-button(user={ _user })
p.empty(if={ !loading && users.length == 0 })
| いません!
p.loading(if={ loading })
i.fa.fa-spinner.fa-pulse.fa-fw
| 読み込んでいます
mk-ellipsis
style.
display block
background #fff
> .title
margin 0
padding 0 16px
line-height 42px
font-size 0.9em
font-weight bold
color #888
border-bottom solid 1px #eee
> i
margin-right 4px
> button
position absolute
z-index 2
top 0
right 0
padding 0
width 42px
font-size 0.9em
line-height 42px
color #ccc
&:hover
color #aaa
&:active
color #999
> .user
padding 16px
border-bottom solid 1px #eee
&:last-child
border-bottom none
&:after
content ""
<mk-user-recommendation-home-widget>
<p class="title"><i class="fa fa-users"></i>おすすめユーザー</p>
<button onclick="{ refresh }" title="他を見る"><i class="fa fa-refresh"></i></button>
<div class="user" if="{ !loading &amp;&amp; users.length != 0 }" each="{ _user in users }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + _user.username }"><img class="avatar" src="{ _user.avatar_url + '?thumbnail&amp;size=42' }" alt="" data-user-preview="{ _user.id }"/></a>
<div class="body"><a class="name" href="{ CONFIG.url + '/' + _user.username }" data-user-preview="{ _user.id }">{ _user.name }</a>
<p class="username">@{ _user.username }</p>
</div>
<mk-follow-button user="{ _user }"></mk-follow-button>
</div>
<p class="empty" if="{ !loading &amp;&amp; users.length == 0 }">いません!</p>
<p class="loading" if="{ loading }"><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます
<mk-ellipsis></mk-ellipsis>
</p>
<style type="stylus">
:scope
display block
clear both
background #fff
> .avatar-anchor
display block
float left
margin 0 12px 0 0
> .title
margin 0
padding 0 16px
line-height 42px
font-size 0.9em
font-weight bold
color #888
border-bottom solid 1px #eee
> .avatar
display block
> i
margin-right 4px
> button
position absolute
z-index 2
top 0
right 0
padding 0
width 42px
height 42px
margin 0
border-radius 8px
vertical-align bottom
> .body
float left
width calc(100% - 54px)
> .name
margin 0
font-size 16px
line-height 24px
color #555
> .username
display block
margin 0
font-size 15px
line-height 16px
font-size 0.9em
line-height 42px
color #ccc
> mk-follow-button
position absolute
top 16px
right 16px
&:hover
color #aaa
> .empty
margin 0
padding 16px
text-align center
color #aaa
&:active
color #999
> .loading
margin 0
padding 16px
text-align center
color #aaa
> .user
padding 16px
border-bottom solid 1px #eee
> i
margin-right 4px
&:last-child
border-bottom none
script.
@mixin \api
@mixin \user-preview
&:after
content ""
display block
clear both
@users = null
@loading = true
> .avatar-anchor
display block
float left
margin 0 12px 0 0
@limit = 3users
@page = 0
> .avatar
display block
width 42px
height 42px
margin 0
border-radius 8px
vertical-align bottom
@on \mount ~>
@fetch!
@clock = set-interval ~>
if @users.length < @limit
@fetch true
, 60000ms
> .body
float left
width calc(100% - 54px)
@on \unmount ~>
clear-interval @clock
> .name
margin 0
font-size 16px
line-height 24px
color #555
> .username
display block
margin 0
font-size 15px
line-height 16px
color #ccc
> mk-follow-button
position absolute
top 16px
right 16px
> .empty
margin 0
padding 16px
text-align center
color #aaa
> .loading
margin 0
padding 16px
text-align center
color #aaa
> i
margin-right 4px
</style>
<script>
@mixin \api
@mixin \user-preview
@fetch = (quiet = false) ~>
@loading = true
@users = null
if not quiet then @update!
@api \users/recommendation do
limit: @limit
offset: @limit * @page
.then (users) ~>
@loading = false
@users = users
@update!
.catch (err, text-status) ->
console.error err
@loading = true
@refresh = ~>
if @users.length < @limit
@page = 0
else
@page++
@fetch!
@limit = 3users
@page = 0
@on \mount ~>
@fetch!
@clock = set-interval ~>
if @users.length < @limit
@fetch true
, 60000ms
@on \unmount ~>
clear-interval @clock
@fetch = (quiet = false) ~>
@loading = true
@users = null
if not quiet then @update!
@api \users/recommendation do
limit: @limit
offset: @limit * @page
.then (users) ~>
@loading = false
@users = users
@update!
.catch (err, text-status) ->
console.error err
@refresh = ~>
if @users.length < @limit
@page = 0
else
@page++
@fetch!
</script>
</mk-user-recommendation-home-widget>

View File

@ -1,86 +1,91 @@
mk-home
div.main
div.left@left
main
mk-timeline-home-widget@tl(if={ mode == 'timeline' })
mk-mentions-home-widget@tl(if={ mode == 'mentions' })
div.right@right
mk-detect-slow-internet-connection-notice
style.
display block
> .main
margin 0 auto
max-width 1200px
&:after
content ""
<mk-home>
<div class="main">
<div class="left" ref="left"></div>
<main>
<mk-timeline-home-widget ref="tl" if="{ mode == 'timeline' }"></mk-timeline-home-widget>
<mk-mentions-home-widget ref="tl" if="{ mode == 'mentions' }"></mk-mentions-home-widget>
</main>
<div class="right" ref="right"></div>
</div>
<mk-detect-slow-internet-connection-notice></mk-detect-slow-internet-connection-notice>
<style type="stylus">
:scope
display block
clear both
> *
float left
> *
display block
//border solid 1px #eaeaea
border solid 1px rgba(0, 0, 0, 0.075)
border-radius 6px
overflow hidden
&:not(:last-child)
margin-bottom 16px
> main
padding 16px
width calc(100% - 275px * 2)
> *:not(main)
width 275px
> .left
padding 16px 0 16px 16px
> .right
padding 16px 16px 16px 0
@media (max-width 1100px)
> *:not(main)
display none
> main
float none
width 100%
max-width 700px
> .main
margin 0 auto
max-width 1200px
script.
@mixin \i
@mode = @opts.mode || \timeline
&:after
content ""
display block
clear both
# https://github.com/riot/riot/issues/2080
if @mode == '' then @mode = \timeline
> *
float left
@home = []
> *
display block
//border solid 1px #eaeaea
border solid 1px rgba(0, 0, 0, 0.075)
border-radius 6px
overflow hidden
@on \mount ~>
@refs.tl.on \loaded ~>
@trigger \loaded
&:not(:last-child)
margin-bottom 16px
@I.data.home.for-each (widget) ~>
try
el = document.create-element \mk- + widget.name + \-home-widget
switch widget.place
| \left => @refs.left.append-child el
| \right => @refs.right.append-child el
@home.push (riot.mount el, do
id: widget.id
data: widget.data
.0)
catch e
# noop
> main
padding 16px
width calc(100% - 275px * 2)
@on \unmount ~>
@home.for-each (widget) ~>
widget.unmount!
> *:not(main)
width 275px
> .left
padding 16px 0 16px 16px
> .right
padding 16px 16px 16px 0
@media (max-width 1100px)
> *:not(main)
display none
> main
float none
width 100%
max-width 700px
margin 0 auto
</style>
<script>
@mixin \i
@mode = @opts.mode || \timeline
# https://github.com/riot/riot/issues/2080
if @mode == '' then @mode = \timeline
@home = []
@on \mount ~>
@refs.tl.on \loaded ~>
@trigger \loaded
@I.data.home.for-each (widget) ~>
try
el = document.create-element \mk- + widget.name + \-home-widget
switch widget.place
| \left => @refs.left.append-child el
| \right => @refs.right.append-child el
@home.push (riot.mount el, do
id: widget.id
data: widget.data
.0)
catch e
# noop
@on \unmount ~>
@home.for-each (widget) ~>
widget.unmount!
</script>
</mk-home>

View File

@ -1,73 +1,75 @@
mk-image-dialog
div.bg@bg(onclick={ close })
img@img(src={ image.url }, alt={ image.name }, title={ image.name }, onclick={ close })
<mk-image-dialog>
<div class="bg" ref="bg" onclick="{ close }"></div><img ref="img" src="{ image.url }" alt="{ image.name }" title="{ image.name }" onclick="{ close }"/>
<style type="stylus">
:scope
display block
position fixed
z-index 2048
top 0
left 0
width 100%
height 100%
opacity 0
style.
display block
position fixed
z-index 2048
top 0
left 0
width 100%
height 100%
opacity 0
> .bg
display block
position fixed
z-index 1
top 0
left 0
width 100%
height 100%
background rgba(0, 0, 0, 0.7)
> .bg
display block
position fixed
z-index 1
top 0
left 0
width 100%
height 100%
background rgba(0, 0, 0, 0.7)
> img
position fixed
z-index 2
top 0
right 0
bottom 0
left 0
max-width 100%
max-height 100%
margin auto
cursor zoom-out
> img
position fixed
z-index 2
top 0
right 0
bottom 0
left 0
max-width 100%
max-height 100%
margin auto
cursor zoom-out
</style>
<script>
@image = @opts.image
script.
@image = @opts.image
@on \mount ~>
Velocity @root, {
opacity: 1
} {
duration: 100ms
easing: \linear
}
@on \mount ~>
Velocity @root, {
opacity: 1
} {
duration: 100ms
easing: \linear
}
#Velocity @img, {
# scale: 1
# opacity: 1
#} {
# duration: 200ms
# easing: \ease-out
#}
#Velocity @img, {
# scale: 1
# opacity: 1
#} {
# duration: 200ms
# easing: \ease-out
#}
@close = ~>
Velocity @root, {
opacity: 0
} {
duration: 100ms
easing: \linear
complete: ~> @unmount!
}
@close = ~>
Velocity @root, {
opacity: 0
} {
duration: 100ms
easing: \linear
complete: ~> @unmount!
}
#Velocity @img, {
# scale: 0.9
# opacity: 0
#} {
# duration: 200ms
# easing: \ease-in
# complete: ~>
# @unmount!
#}
#Velocity @img, {
# scale: 0.9
# opacity: 0
#} {
# duration: 200ms
# easing: \ease-in
# complete: ~>
# @unmount!
#}
</script>
</mk-image-dialog>

View File

@ -1,43 +1,45 @@
mk-images-viewer
div.image@view(onmousemove={ mousemove }, style={ 'background-image: url(' + image.url + '?thumbnail' }, onclick={ click })
img(src={ image.url + '?thumbnail&size=512' }, alt={ image.name }, title={ image.name })
style.
display block
padding 8px
overflow hidden
box-shadow 0 0 4px rgba(0, 0, 0, 0.2)
border-radius 4px
> .image
cursor zoom-in
> img
<mk-images-viewer>
<div class="image" ref="view" onmousemove="{ mousemove }" style="{ 'background-image: url(' + image.url + '?thumbnail' }" onclick="{ click }"><img src="{ image.url + '?thumbnail&amp;size=512' }" alt="{ image.name }" title="{ image.name }"/></div>
<style type="stylus">
:scope
display block
max-height 256px
max-width 100%
margin 0 auto
padding 8px
overflow hidden
box-shadow 0 0 4px rgba(0, 0, 0, 0.2)
border-radius 4px
&:hover
> img
visibility hidden
> .image
cursor zoom-in
&:not(:hover)
background-image none !important
> img
display block
max-height 256px
max-width 100%
margin 0 auto
script.
@images = @opts.images
@image = @images.0
&:hover
> img
visibility hidden
@mousemove = (e) ~>
rect = @refs.view.get-bounding-client-rect!
mouse-x = e.client-x - rect.left
mouse-y = e.client-y - rect.top
xp = mouse-x / @refs.view.offset-width * 100
yp = mouse-y / @refs.view.offset-height * 100
@refs.view.style.background-position = xp + '% ' + yp + '%'
&:not(:hover)
background-image none !important
@click = ~>
dialog = document.body.append-child document.create-element \mk-image-dialog
riot.mount dialog, do
image: @image
</style>
<script>
@images = @opts.images
@image = @images.0
@mousemove = (e) ~>
rect = @refs.view.get-bounding-client-rect!
mouse-x = e.client-x - rect.left
mouse-y = e.client-y - rect.top
xp = mouse-x / @refs.view.offset-width * 100
yp = mouse-y / @refs.view.offset-height * 100
@refs.view.style.background-position = xp + '% ' + yp + '%'
@click = ~>
dialog = document.body.append-child document.create-element \mk-image-dialog
riot.mount dialog, do
image: @image
</script>
</mk-images-viewer>

View File

@ -1,156 +1,157 @@
mk-input-dialog
mk-window@window(is-modal={ true }, width={ '500px' })
<yield to="header">
i.fa.fa-i-cursor
| { parent.title }
</yield>
<yield to="content">
div.body
input@text(oninput={ parent.update }, onkeydown={ parent.on-keydown }, placeholder={ parent.placeholder })
div.action
button.cancel(onclick={ parent.cancel }) キャンセル
button.ok(disabled={ !parent.allow-empty && refs.text.value.length == 0 }, onclick={ parent.ok }) 決定
</yield>
<mk-input-dialog>
<mk-window ref="window" is-modal="{ true }" width="{ '500px' }"><yield to="header"><i class="fa fa-i-cursor"></i>{ parent.title }</yield>
<yield to="content">
<div class="body">
<input ref="text" oninput="{ parent.update }" onkeydown="{ parent.onKeydown }" placeholder="{ parent.placeholder }"/>
</div>
<div class="action">
<button class="cancel" onclick="{ parent.cancel }">キャンセル</button>
<button class="ok" disabled="{ !parent.allowEmpty &amp;&amp; refs.text.value.length == 0 }" onclick="{ parent.ok }">決定</button>
</div></yield>
</mk-window>
<style type="stylus">
:scope
display block
style.
display block
> mk-window
[data-yield='header']
> i
margin-right 4px
> mk-window
[data-yield='header']
> i
margin-right 4px
[data-yield='content']
> .body
padding 16px
[data-yield='content']
> .body
padding 16px
> input
display block
padding 8px
margin 0
width 100%
max-width 100%
min-width 100%
font-size 1em
color #333
background #fff
outline none
border solid 1px rgba($theme-color, 0.1)
border-radius 4px
transition border-color .3s ease
> input
display block
padding 8px
margin 0
width 100%
max-width 100%
min-width 100%
font-size 1em
color #333
background #fff
outline none
border solid 1px rgba($theme-color, 0.1)
border-radius 4px
transition border-color .3s ease
&:hover
border-color rgba($theme-color, 0.2)
transition border-color .1s ease
&:hover
border-color rgba($theme-color, 0.2)
transition border-color .1s ease
&:focus
color $theme-color
border-color rgba($theme-color, 0.5)
transition border-color 0s ease
&:focus
color $theme-color
border-color rgba($theme-color, 0.5)
transition border-color 0s ease
&::-webkit-input-placeholder
color rgba($theme-color, 0.3)
&::-webkit-input-placeholder
color rgba($theme-color, 0.3)
> .action
height 72px
background lighten($theme-color, 95%)
> .action
height 72px
background lighten($theme-color, 95%)
.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
.ok
.cancel
display block
position absolute
top -5px
right -5px
bottom -5px
left -5px
border 2px solid rgba($theme-color, 0.3)
border-radius 8px
bottom 16px
cursor pointer
padding 0
margin 0
width 120px
height 40px
font-size 1em
outline none
border-radius 4px
&:disabled
opacity 0.7
cursor default
&: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
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%)
&:disabled
opacity 0.7
cursor default
&:not(:disabled)
font-weight bold
.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%)
&:hover:not(:disabled)
background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%)
border-color $theme-color
&:not(:disabled)
font-weight bold
&:active:not(:disabled)
background $theme-color
border-color $theme-color
&:hover:not(:disabled)
background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%)
border-color $theme-color
.cancel
right 148px
color #888
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
border solid 1px #e2e2e2
&:active:not(:disabled)
background $theme-color
border-color $theme-color
&:hover
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
border-color #dcdcdc
.cancel
right 148px
color #888
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
border solid 1px #e2e2e2
&:active
background #ececec
border-color #dcdcdc
&:hover
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
border-color #dcdcdc
script.
@done = false
&:active
background #ececec
border-color #dcdcdc
@title = @opts.title
@placeholder = @opts.placeholder
@default = @opts.default
@allow-empty = if @opts.allow-empty? then @opts.allow-empty else true
@on \mount ~>
@text = @refs.window.refs.text
if @default?
@text.value = @default
@text.focus!
@refs.window.on \closing ~>
if @done
@opts.on-ok @text.value
else
if @opts.on-cancel?
@opts.on-cancel!
@refs.window.on \closed ~>
@unmount!
@cancel = ~>
</style>
<script>
@done = false
@refs.window.close!
@ok = ~>
if not @allow-empty and @text.value == '' then return
@done = true
@refs.window.close!
@title = @opts.title
@placeholder = @opts.placeholder
@default = @opts.default
@allow-empty = if @opts.allow-empty? then @opts.allow-empty else true
@on-keydown = (e) ~>
if e.which == 13 # Enter
e.prevent-default!
e.stop-propagation!
@ok!
@on \mount ~>
@text = @refs.window.refs.text
if @default?
@text.value = @default
@text.focus!
@refs.window.on \closing ~>
if @done
@opts.on-ok @text.value
else
if @opts.on-cancel?
@opts.on-cancel!
@refs.window.on \closed ~>
@unmount!
@cancel = ~>
@done = false
@refs.window.close!
@ok = ~>
if not @allow-empty and @text.value == '' then return
@done = true
@refs.window.close!
@on-keydown = (e) ~>
if e.which == 13 # Enter
e.prevent-default!
e.stop-propagation!
@ok!
</script>
</mk-input-dialog>

View File

@ -1,100 +1,98 @@
mk-list-user
a.avatar-anchor(href={ CONFIG.url + '/' + user.username })
img.avatar(src={ user.avatar_url + '?thumbnail&size=64' }, alt='avatar')
div.main
header
div.left
a.name(href={ CONFIG.url + '/' + user.username })
| { user.name }
span.username
| @{ user.username }
div.body
p.followed(if={ user.is_followed }) フォローされています
div.bio { user.bio }
mk-follow-button(user={ user })
style.
display block
margin 0
padding 16px
font-size 16px
&:after
content ""
display block
clear both
> .avatar-anchor
display block
float left
margin 0 16px 0 0
> .avatar
<mk-list-user><a class="avatar-anchor" href="{ CONFIG.url + '/' + user.username }"><img class="avatar" src="{ user.avatar_url + '?thumbnail&amp;size=64' }" alt="avatar"/></a>
<div class="main">
<header>
<div class="left"><a class="name" href="{ CONFIG.url + '/' + user.username }">{ user.name }</a><span class="username">@{ user.username }</span></div>
</header>
<div class="body">
<p class="followed" if="{ user.is_followed }">フォローされています</p>
<div class="bio">{ user.bio }</div>
</div>
</div>
<mk-follow-button user="{ user }"></mk-follow-button>
<style type="stylus">
:scope
display block
width 58px
height 58px
margin 0
border-radius 8px
vertical-align bottom
> .main
float left
width calc(100% - 74px)
> header
margin-bottom 2px
white-space nowrap
padding 16px
font-size 16px
&:after
content ""
display block
clear both
> .left
float left
> .name
display inline
margin 0
padding 0
color #777
font-size 1em
font-weight 700
text-align left
text-decoration none
&:hover
text-decoration underline
> .username
text-align left
margin 0 0 0 8px
color #ccc
> .body
> .followed
display inline-block
margin 0 0 4px 0
padding 2px 8px
vertical-align top
font-size 10px
color #71afc7
background #eefaff
border-radius 4px
> .bio
cursor default
> .avatar-anchor
display block
margin 0
padding 0
word-wrap break-word
font-size 1.1em
color #717171
float left
margin 0 16px 0 0
> mk-follow-button
position absolute
top 16px
right 16px
> .avatar
display block
width 58px
height 58px
margin 0
border-radius 8px
vertical-align bottom
script.
@user = @opts.user
> .main
float left
width calc(100% - 74px)
> header
margin-bottom 2px
white-space nowrap
&:after
content ""
display block
clear both
> .left
float left
> .name
display inline
margin 0
padding 0
color #777
font-size 1em
font-weight 700
text-align left
text-decoration none
&:hover
text-decoration underline
> .username
text-align left
margin 0 0 0 8px
color #ccc
> .body
> .followed
display inline-block
margin 0 0 4px 0
padding 2px 8px
vertical-align top
font-size 10px
color #71afc7
background #eefaff
border-radius 4px
> .bio
cursor default
display block
margin 0
padding 0
word-wrap break-word
font-size 1.1em
color #717171
> mk-follow-button
position absolute
top 16px
right 16px
</style>
<script>@user = @opts.user</script>
</mk-list-user>

View File

@ -1,162 +1,161 @@
mk-messaging-form
textarea@text(onkeypress={ onkeypress }, onpaste={ onpaste }, placeholder='ここにメッセージを入力')
div.files
mk-uploader@uploader
button.send(onclick={ send }, disabled={ sending }, title='メッセージを送信')
i.fa.fa-paper-plane(if={ !sending })
i.fa.fa-spinner.fa-spin(if={ sending })
button.attach-from-local(type='button', title='PCから画像を添付する')
i.fa.fa-upload
button.attach-from-drive(type='button', title='アルバムから画像を添付する')
i.fa.fa-folder-open
input(name='file', type='file', accept='image/*')
style.
display block
> textarea
cursor auto
display block
width 100%
min-width 100%
max-width 100%
height 64px
margin 0
padding 8px
font-size 1em
color #000
outline none
border none
border-top solid 1px #eee
border-radius 0
box-shadow none
background transparent
> .send
position absolute
bottom 0
right 0
margin 0
padding 10px 14px
line-height 1em
font-size 1em
color #aaa
transition color 0.1s ease
&:hover
color $theme-color
&:active
color darken($theme-color, 10%)
transition color 0s ease
.files
display block
margin 0
padding 0 8px
list-style none
&:after
content ''
<mk-messaging-form>
<textarea ref="text" onkeypress="{ onkeypress }" onpaste="{ onpaste }" placeholder="ここにメッセージを入力"></textarea>
<div class="files"></div>
<mk-uploader ref="uploader"></mk-uploader>
<button class="send" onclick="{ send }" disabled="{ sending }" title="メッセージを送信"><i class="fa fa-paper-plane" if="{ !sending }"></i><i class="fa fa-spinner fa-spin" if="{ sending }"></i></button>
<button class="attach-from-local" type="button" title="PCから画像を添付する"><i class="fa fa-upload"></i></button>
<button class="attach-from-drive" type="button" title="アルバムから画像を添付する"><i class="fa fa-folder-open"></i></button>
<input name="file" type="file" accept="image/*"/>
<style type="stylus">
:scope
display block
clear both
> li
display block
float left
margin 4px
padding 0
width 64px
height 64px
background-color #eee
background-repeat no-repeat
background-position center center
background-size cover
cursor move
&:hover
> .remove
display block
> .remove
display none
position absolute
right -6px
top -6px
> textarea
cursor auto
display block
width 100%
min-width 100%
max-width 100%
height 64px
margin 0
padding 0
background transparent
padding 8px
font-size 1em
color #000
outline none
border none
border-top solid 1px #eee
border-radius 0
box-shadow none
cursor pointer
background transparent
.attach-from-local
.attach-from-drive
margin 0
padding 10px 14px
line-height 1em
font-size 1em
font-weight normal
text-decoration none
color #aaa
transition color 0.1s ease
> .send
position absolute
bottom 0
right 0
margin 0
padding 10px 14px
line-height 1em
font-size 1em
color #aaa
transition color 0.1s ease
&:hover
color $theme-color
&:hover
color $theme-color
&:active
color darken($theme-color, 10%)
transition color 0s ease
&:active
color darken($theme-color, 10%)
transition color 0s ease
input[type=file]
display none
.files
display block
margin 0
padding 0 8px
list-style none
script.
@mixin \api
&:after
content ''
display block
clear both
@user = @opts.user
> li
display block
float left
margin 4px
padding 0
width 64px
height 64px
background-color #eee
background-repeat no-repeat
background-position center center
background-size cover
cursor move
@onpaste = (e) ~>
data = e.clipboard-data
items = data.items
for i from 0 to items.length - 1
item = items[i]
switch (item.kind)
| \file =>
@upload item.get-as-file!
&:hover
> .remove
display block
@onkeypress = (e) ~>
if (e.which == 10 || e.which == 13) && e.ctrl-key
@send!
> .remove
display none
position absolute
right -6px
top -6px
margin 0
padding 0
background transparent
outline none
border none
border-radius 0
box-shadow none
cursor pointer
@select-file = ~>
@refs.file.click!
.attach-from-local
.attach-from-drive
margin 0
padding 10px 14px
line-height 1em
font-size 1em
font-weight normal
text-decoration none
color #aaa
transition color 0.1s ease
@select-file-from-drive = ~>
browser = document.body.append-child document.create-element \mk-select-file-from-drive-window
event = riot.observable!
riot.mount browser, do
multiple: true
event: event
event.one \selected (files) ~>
files.for-each @add-file
&:hover
color $theme-color
@send = ~>
@sending = true
@api \messaging/messages/create do
user_id: @user.id
text: @refs.text.value
.then (message) ~>
@clear!
.catch (err) ~>
console.error err
.then ~>
@sending = false
&:active
color darken($theme-color, 10%)
transition color 0s ease
input[type=file]
display none
</style>
<script>
@mixin \api
@user = @opts.user
@onpaste = (e) ~>
data = e.clipboard-data
items = data.items
for i from 0 to items.length - 1
item = items[i]
switch (item.kind)
| \file =>
@upload item.get-as-file!
@onkeypress = (e) ~>
if (e.which == 10 || e.which == 13) && e.ctrl-key
@send!
@select-file = ~>
@refs.file.click!
@select-file-from-drive = ~>
browser = document.body.append-child document.create-element \mk-select-file-from-drive-window
event = riot.observable!
riot.mount browser, do
multiple: true
event: event
event.one \selected (files) ~>
files.for-each @add-file
@send = ~>
@sending = true
@api \messaging/messages/create do
user_id: @user.id
text: @refs.text.value
.then (message) ~>
@clear!
.catch (err) ~>
console.error err
.then ~>
@sending = false
@update!
@clear = ~>
@refs.text.value = ''
@files = []
@update!
@clear = ~>
@refs.text.value = ''
@files = []
@update!
</script>
</mk-messaging-form>

View File

@ -1,302 +1,301 @@
mk-messaging
div.search
div.form
label(for='search-input')
i.fa.fa-search
input@search-input(type='search', oninput={ search }, placeholder='ユーザーを探す')
div.result
ol.users(if={ search-result.length > 0 })
li(each={ user in search-result })
a(onclick={ user._click })
img.avatar(src={ user.avatar_url + '?thumbnail&size=32' }, alt='')
span.name { user.name }
span.username @{ user.username }
div.main
div.history(if={ history.length > 0 })
virtual(each={ history })
a.user(data-is-me={ is_me }, data-is-read={ is_read }, onclick={ _click }): div
img.avatar(src={ (is_me ? recipient.avatar_url : user.avatar_url) + '?thumbnail&size=64' }, alt='')
header
span.name { is_me ? recipient.name : user.name }
span.username { '@' + (is_me ? recipient.username : user.username ) }
mk-time(time={ created_at })
div.body
p.text
span.me(if={ is_me }) あなた:
| { text }
p.no-history(if={ history.length == 0 })
| 履歴はありません。
br
| ユーザーを検索して、いつでもメッセージを送受信できます。
<mk-messaging>
<div class="search">
<div class="form">
<label for="search-input"><i class="fa fa-search"></i></label>
<input ref="searchInput" type="search" oninput="{ search }" placeholder="ユーザーを探す"/>
</div>
<div class="result">
<ol class="users" if="{ searchResult.length &gt; 0 }">
<li each="{ user in searchResult }"><a onclick="{ user._click }"><img class="avatar" src="{ user.avatar_url + '?thumbnail&amp;size=32' }" alt=""/><span class="name">{ user.name }</span><span class="username">@{ user.username }</span></a></li>
</ol>
</div>
</div>
<div class="main">
<div class="history" if="{ history.length &gt; 0 }">
<virtual each="{ history }"><a class="user" data-is-me="{ is_me }" data-is-read="{ is_read }" onclick="{ _click }">
<div><img class="avatar" src="{ (is_me ? recipient.avatar_url : user.avatar_url) + '?thumbnail&amp;size=64' }" alt=""/>
<header><span class="name">{ is_me ? recipient.name : user.name }</span><span class="username">{ '@' + (is_me ? recipient.username : user.username ) }</span>
<mk-time time="{ created_at }"></mk-time>
</header>
<div class="body">
<p class="text"><span class="me" if="{ is_me }">あなた:</span>{ text }</p>
</div>
</div></a></virtual>
</div>
<p class="no-history" if="{ history.length == 0 }">履歴はありません。<br/>ユーザーを検索して、いつでもメッセージを送受信できます。</p>
</div>
<style type="stylus">
:scope
display block
style.
display block
> .search
display block
position absolute
top 0
left 0
z-index 1
width 100%
background #fff
box-shadow 0 0px 2px rgba(0, 0, 0, 0.2)
> .form
padding 8px
background #f7f7f7
> label
> .search
display block
position absolute
top 0
left 8px
left 0
z-index 1
height 100%
width 38px
pointer-events none
> i
display block
position absolute
top 0
right 0
bottom 0
left 0
width 1em
height 1em
margin auto
color #555
> input
margin 0
padding 0 12px 0 38px
width 100%
font-size 1em
line-height 38px
color #000
outline none
border solid 1px #eee
border-radius 5px
box-shadow none
transition color 0.5s ease, border 0.5s ease
&:hover
border solid 1px #ddd
transition border 0.2s ease
&:focus
color darken($theme-color, 20%)
border solid 1px $theme-color
transition color 0, border 0
> .result
display block
top 0
left 0
z-index 2
width 100%
margin 0
padding 0
background #fff
> .users
margin 0
padding 0
list-style none
> li
> a
display inline-block
z-index 1
width 100%
padding 8px 32px
vertical-align top
white-space nowrap
overflow hidden
color rgba(0, 0, 0, 0.8)
text-decoration none
transition none
&:hover
color #fff
background $theme-color
.name
color #fff
.username
color #fff
&:active
color #fff
background darken($theme-color, 10%)
.name
color #fff
.username
color #fff
.avatar
vertical-align middle
min-width 32px
min-height 32px
max-width 32px
max-height 32px
margin 0 8px 0 0
border-radius 6px
.name
margin 0 8px 0 0
/*font-weight bold*/
font-weight normal
color rgba(0, 0, 0, 0.8)
.username
font-weight normal
color rgba(0, 0, 0, 0.3)
> .main
padding-top 56px
> .history
> a
display block
padding 20px 30px
text-decoration none
background #fff
border-bottom solid 1px #eee
box-shadow 0 0px 2px rgba(0, 0, 0, 0.2)
*
pointer-events none
user-select none
> .form
padding 8px
background #f7f7f7
&:hover
background #fafafa
> label
display block
position absolute
top 0
left 8px
z-index 1
height 100%
width 38px
pointer-events none
> .avatar
filter saturate(200%)
&:active
background #eee
&[data-is-read]
&[data-is-me]
opacity 0.8
&:not([data-is-me]):not([data-is-read])
background-image url("/_/resources/desktop/unread.svg")
background-repeat no-repeat
background-position 0 center
&:after
content ""
display block
clear both
> div
max-width 500px
margin 0 auto
> header
margin-bottom 2px
white-space nowrap
overflow hidden
> .name
text-align left
display inline
margin 0
padding 0
font-size 1em
color rgba(0, 0, 0, 0.9)
font-weight bold
transition all 0.1s ease
> .username
text-align left
margin 0 0 0 8px
color rgba(0, 0, 0, 0.5)
> mk-time
> i
display block
position absolute
top 0
right 0
display inline
color rgba(0, 0, 0, 0.5)
font-size small
bottom 0
left 0
width 1em
height 1em
margin auto
color #555
> .avatar
float left
width 54px
height 54px
margin 0 16px 0 0
border-radius 8px
transition all 0.1s ease
> input
margin 0
padding 0 12px 0 38px
width 100%
font-size 1em
line-height 38px
color #000
outline none
border solid 1px #eee
border-radius 5px
box-shadow none
transition color 0.5s ease, border 0.5s ease
> .body
&:hover
border solid 1px #ddd
transition border 0.2s ease
> .text
&:focus
color darken($theme-color, 20%)
border solid 1px $theme-color
transition color 0, border 0
> .result
display block
top 0
left 0
z-index 2
width 100%
margin 0
padding 0
background #fff
> .users
margin 0
padding 0
list-style none
> li
> a
display inline-block
z-index 1
width 100%
padding 8px 32px
vertical-align top
white-space nowrap
overflow hidden
color rgba(0, 0, 0, 0.8)
text-decoration none
transition none
&:hover
color #fff
background $theme-color
.name
color #fff
.username
color #fff
&:active
color #fff
background darken($theme-color, 10%)
.name
color #fff
.username
color #fff
.avatar
vertical-align middle
min-width 32px
min-height 32px
max-width 32px
max-height 32px
margin 0 8px 0 0
border-radius 6px
.name
margin 0 8px 0 0
/*font-weight bold*/
font-weight normal
color rgba(0, 0, 0, 0.8)
.username
font-weight normal
color rgba(0, 0, 0, 0.3)
> .main
padding-top 56px
> .history
> a
display block
padding 20px 30px
text-decoration none
background #fff
border-bottom solid 1px #eee
*
pointer-events none
user-select none
&:hover
background #fafafa
> .avatar
filter saturate(200%)
&:active
background #eee
&[data-is-read]
&[data-is-me]
opacity 0.8
&:not([data-is-me]):not([data-is-read])
background-image url("/_/resources/desktop/unread.svg")
background-repeat no-repeat
background-position 0 center
&:after
content ""
display block
margin 0 0 0 0
padding 0
overflow hidden
word-wrap break-word
font-size 1.1em
color rgba(0, 0, 0, 0.8)
clear both
.me
color rgba(0, 0, 0, 0.4)
> div
max-width 500px
margin 0 auto
> .image
display block
max-width 100%
max-height 512px
> header
margin-bottom 2px
white-space nowrap
overflow hidden
> .no-history
margin 0
padding 2em 1em
text-align center
color #999
font-weight 500
> .name
text-align left
display inline
margin 0
padding 0
font-size 1em
color rgba(0, 0, 0, 0.9)
font-weight bold
transition all 0.1s ease
script.
@mixin \i
@mixin \api
> .username
text-align left
margin 0 0 0 8px
color rgba(0, 0, 0, 0.5)
@search-result = []
> mk-time
position absolute
top 0
right 0
display inline
color rgba(0, 0, 0, 0.5)
font-size small
@on \mount ~>
@api \messaging/history
.then (history) ~>
@is-loading = false
history.for-each (message) ~>
message.is_me = message.user_id == @I.id
message._click = ~>
if message.is_me
@trigger \navigate-user message.recipient
else
@trigger \navigate-user message.user
@history = history
@update!
.catch (err) ~>
console.error err
> .avatar
float left
width 54px
height 54px
margin 0 16px 0 0
border-radius 8px
transition all 0.1s ease
@search = ~>
q = @refs.search-input.value
if q == ''
@search-result = []
else
@api \users/search do
query: q
.then (users) ~>
users.for-each (user) ~>
user._click = ~>
@trigger \navigate-user user
@search-result = []
@search-result = users
> .body
> .text
display block
margin 0 0 0 0
padding 0
overflow hidden
word-wrap break-word
font-size 1.1em
color rgba(0, 0, 0, 0.8)
.me
color rgba(0, 0, 0, 0.4)
> .image
display block
max-width 100%
max-height 512px
> .no-history
margin 0
padding 2em 1em
text-align center
color #999
font-weight 500
</style>
<script>
@mixin \i
@mixin \api
@search-result = []
@on \mount ~>
@api \messaging/history
.then (history) ~>
@is-loading = false
history.for-each (message) ~>
message.is_me = message.user_id == @I.id
message._click = ~>
if message.is_me
@trigger \navigate-user message.recipient
else
@trigger \navigate-user message.user
@history = history
@update!
.catch (err) ~>
console.error err
@search = ~>
q = @refs.search-input.value
if q == ''
@search-result = []
else
@api \users/search do
query: q
.then (users) ~>
users.for-each (user) ~>
user._click = ~>
@trigger \navigate-user user
@search-result = []
@search-result = users
@update!
.catch (err) ~>
console.error err
</script>
</mk-messaging>

View File

@ -1,227 +1,230 @@
mk-messaging-message(data-is-me={ message.is_me })
a.avatar-anchor(href={ CONFIG.url + '/' + message.user.username }, title={ message.user.username }, target='_blank')
img.avatar(src={ message.user.avatar_url + '?thumbnail&size=64' }, alt='')
div.content-container
div.balloon
p.read(if={ message.is_me && message.is_read }) 既読
button.delete-button(if={ message.is_me }, title='メッセージを削除')
img(src='/_/resources/desktop/messaging/delete.png', alt='Delete')
div.content(if={ !message.is_deleted })
div@text
div.image(if={ message.file })
img(src={ message.file.url }, alt='image', title={ message.file.name })
div.content(if={ message.is_deleted })
p.is-deleted このメッセージは削除されました
footer
mk-time(time={ message.created_at })
i.fa.fa-pencil.is-edited(if={ message.is_edited })
<mk-messaging-message data-is-me="{ message.is_me }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + message.user.username }" title="{ message.user.username }" target="_blank"><img class="avatar" src="{ message.user.avatar_url + '?thumbnail&amp;size=64' }" alt=""/></a>
<div class="content-container">
<div class="balloon">
<p class="read" if="{ message.is_me &amp;&amp; message.is_read }">既読</p>
<button class="delete-button" if="{ message.is_me }" title="メッセージを削除"><img src="/_/resources/desktop/messaging/delete.png" alt="Delete"/></button>
<div class="content" if="{ !message.is_deleted }">
<div ref="text"></div>
<div class="image" if="{ message.file }"><img src="{ message.file.url }" alt="image" title="{ message.file.name }"/></div>
</div>
<div class="content" if="{ message.is_deleted }">
<p class="is-deleted">このメッセージは削除されました</p>
</div>
</div>
<footer>
<mk-time time="{ message.created_at }"></mk-time><i class="fa fa-pencil is-edited" if="{ message.is_edited }"></i>
</footer>
</div>
<style type="stylus">
:scope
$me-balloon-color = #23A7B6
style.
$me-balloon-color = #23A7B6
display block
padding 10px 12px 10px 12px
background-color transparent
&:after
content ""
display block
clear both
> .avatar-anchor
display block
> .avatar
display block
min-width 54px
min-height 54px
max-width 54px
max-height 54px
margin 0
border-radius 8px
transition all 0.1s ease
padding 10px 12px 10px 12px
background-color transparent
> .content-container
display block
margin 0 12px
padding 0
max-width calc(100% - 78px)
> .balloon
display block
float inherit
margin 0
padding 0
max-width 100%
min-height 38px
border-radius 16px
&:before
&:after
content ""
pointer-events none
display block
position absolute
top 12px
clear both
&:hover
> .delete-button
> .avatar-anchor
display block
> .avatar
display block
min-width 54px
min-height 54px
max-width 54px
max-height 54px
margin 0
border-radius 8px
transition all 0.1s ease
> .delete-button
display none
position absolute
z-index 1
top -4px
right -4px
margin 0
> .content-container
display block
margin 0 12px
padding 0
cursor pointer
outline none
border none
border-radius 0
box-shadow none
background transparent
max-width calc(100% - 78px)
> img
vertical-align bottom
width 16px
height 16px
cursor pointer
> .read
user-select none
display block
position absolute
z-index 1
bottom -4px
left -12px
margin 0
color rgba(0, 0, 0, 0.5)
font-size 11px
> .content
> .is-deleted
> .balloon
display block
float inherit
margin 0
padding 0
overflow hidden
word-wrap break-word
font-size 1em
color rgba(0, 0, 0, 0.5)
max-width 100%
min-height 38px
border-radius 16px
> [ref='text']
display block
margin 0
padding 8px 16px
overflow hidden
word-wrap break-word
font-size 1em
color rgba(0, 0, 0, 0.8)
&:before
content ""
pointer-events none
display block
position absolute
top 12px
&, *
user-select text
cursor auto
& + .file
&.image
> img
border-radius 0 0 16px 16px
> .file
&.image
> img
&:hover
> .delete-button
display block
max-width 100%
max-height 512px
border-radius 16px
> footer
display block
clear both
margin 0
padding 2px
font-size 10px
color rgba(0, 0, 0, 0.4)
> .delete-button
display none
position absolute
z-index 1
top -4px
right -4px
margin 0
padding 0
cursor pointer
outline none
border none
border-radius 0
box-shadow none
background transparent
> .is-edited
margin-left 4px
> img
vertical-align bottom
width 16px
height 16px
cursor pointer
&:not([data-is-me='true'])
> .avatar-anchor
float left
> .read
user-select none
display block
position absolute
z-index 1
bottom -4px
left -12px
margin 0
color rgba(0, 0, 0, 0.5)
font-size 11px
> .content-container
float left
> .content
> .balloon
background #eee
> .is-deleted
display block
margin 0
padding 0
overflow hidden
word-wrap break-word
font-size 1em
color rgba(0, 0, 0, 0.5)
&:before
left -14px
border-top solid 8px transparent
border-right solid 8px #eee
border-bottom solid 8px transparent
border-left solid 8px transparent
> [ref='text']
display block
margin 0
padding 8px 16px
overflow hidden
word-wrap break-word
font-size 1em
color rgba(0, 0, 0, 0.8)
> footer
text-align left
&, *
user-select text
cursor auto
&[data-is-me='true']
> .avatar-anchor
float right
& + .file
&.image
> img
border-radius 0 0 16px 16px
> .content-container
float right
> .file
&.image
> img
display block
max-width 100%
max-height 512px
border-radius 16px
> .balloon
background $me-balloon-color
> footer
display block
clear both
margin 0
padding 2px
font-size 10px
color rgba(0, 0, 0, 0.4)
&:before
right -14px
left auto
border-top solid 8px transparent
border-right solid 8px transparent
border-bottom solid 8px transparent
border-left solid 8px $me-balloon-color
> .is-edited
margin-left 4px
> .content
&:not([data-is-me='true'])
> .avatar-anchor
float left
> p.is-deleted
color rgba(255, 255, 255, 0.5)
> .content-container
float left
> [ref='text']
&, *
color #fff !important
> .balloon
background #eee
> footer
text-align right
&:before
left -14px
border-top solid 8px transparent
border-right solid 8px #eee
border-bottom solid 8px transparent
border-left solid 8px transparent
&[data-is-deleted='true']
> .content-container
opacity 0.5
> footer
text-align left
script.
@mixin \i
@mixin \text
&[data-is-me='true']
> .avatar-anchor
float right
@message = @opts.message
@message.is_me = @message.user.id == @I.id
> .content-container
float right
@on \mount ~>
if @message.text?
tokens = @analyze @message.text
> .balloon
background $me-balloon-color
@refs.text.innerHTML = @compile tokens
&:before
right -14px
left auto
border-top solid 8px transparent
border-right solid 8px transparent
border-bottom solid 8px transparent
border-left solid 8px $me-balloon-color
@refs.text.children.for-each (e) ~>
if e.tag-name == \MK-URL
riot.mount e
> .content
# URLをプレビュー
tokens
.filter (t) -> t.type == \link
.map (t) ~>
@preview = @refs.text.append-child document.create-element \mk-url-preview
riot.mount @preview, do
url: t.content
> p.is-deleted
color rgba(255, 255, 255, 0.5)
> [ref='text']
&, *
color #fff !important
> footer
text-align right
&[data-is-deleted='true']
> .content-container
opacity 0.5
</style>
<script>
@mixin \i
@mixin \text
@message = @opts.message
@message.is_me = @message.user.id == @I.id
@on \mount ~>
if @message.text?
tokens = @analyze @message.text
@refs.text.innerHTML = @compile tokens
@refs.text.children.for-each (e) ~>
if e.tag-name == \MK-URL
riot.mount e
# URLをプレビュー
tokens
.filter (t) -> t.type == \link
.map (t) ~>
@preview = @refs.text.append-child document.create-element \mk-url-preview
riot.mount @preview, do
url: t.content
</script>
</mk-messaging-message>

View File

@ -1,26 +1,25 @@
mk-messaging-room-window
mk-window@window(is-modal={ false }, width={ '500px' }, height={ '560px' })
<yield to="header">
i.fa.fa-comments
| メッセージ: { parent.user.name }
</yield>
<yield to="content">
mk-messaging-room(user={ parent.user })
</yield>
<mk-messaging-room-window>
<mk-window ref="window" is-modal="{ false }" width="{ '500px' }" height="{ '560px' }"><yield to="header"><i class="fa fa-comments"></i>メッセージ: { parent.user.name }</yield>
<yield to="content">
<mk-messaging-room user="{ parent.user }"></mk-messaging-room></yield>
</mk-window>
<style type="stylus">
:scope
> mk-window
[data-yield='header']
> i
margin-right 4px
style.
> mk-window
[data-yield='header']
> i
margin-right 4px
[data-yield='content']
> mk-messaging-room
height 100%
[data-yield='content']
> mk-messaging-room
height 100%
</style>
<script>
@user = @opts.user
script.
@user = @opts.user
@on \mount ~>
@refs.window.on \closed ~>
@unmount!
@on \mount ~>
@refs.window.on \closed ~>
@unmount!
</script>
</mk-messaging-room-window>

View File

@ -1,227 +1,227 @@
mk-messaging-room
div.stream@stream
p.initializing(if={ init })
i.fa.fa-spinner.fa-spin
| 読み込み中
p.empty(if={ !init && messages.length == 0 })
i.fa.fa-info-circle
| このユーザーとまだ会話したことがありません
virtual(each={ message, i in messages })
mk-messaging-message(message={ message })
p.date(if={ i != messages.length - 1 && message._date != messages[i + 1]._date })
span { messages[i + 1]._datetext }
div.typings
footer
div@notifications
div.grippie(title='ドラッグしてフォームの広さを調整')
mk-messaging-form(user={ user })
style.
display block
> .stream
position absolute
top 0
left 0
width 100%
height calc(100% - 100px)
overflow auto
> .empty
width 100%
margin 0
padding 16px 8px 8px 8px
text-align center
font-size 0.8em
color rgba(0, 0, 0, 0.4)
i
margin-right 4px
> .no-history
<mk-messaging-room>
<div class="stream" ref="stream">
<p class="initializing" if="{ init }"><i class="fa fa-spinner fa-spin"></i>読み込み中</p>
<p class="empty" if="{ !init &amp;&amp; messages.length == 0 }"><i class="fa fa-info-circle"></i>このユーザーとまだ会話したことがありません</p>
<virtual each="{ message, i in messages }">
<mk-messaging-message message="{ message }"></mk-messaging-message>
<p class="date" if="{ i != messages.length - 1 &amp;&amp; message._date != messages[i + 1]._date }"><span>{ messages[i + 1]._datetext }</span></p>
</virtual>
</div>
<div class="typings"></div>
<footer>
<div ref="notifications"></div>
<div class="grippie" title="ドラッグしてフォームの広さを調整"></div>
<mk-messaging-form user="{ user }"></mk-messaging-form>
</footer>
<style type="stylus">
:scope
display block
margin 0
padding 16px
text-align center
font-size 0.8em
color rgba(0, 0, 0, 0.4)
i
margin-right 4px
> .message
// something
> .date
display block
margin 8px 0
text-align center
&:before
content ''
display block
> .stream
position absolute
height 1px
width 90%
top 16px
top 0
left 0
right 0
width 100%
height calc(100% - 100px)
overflow auto
> .empty
width 100%
margin 0
padding 16px 8px 8px 8px
text-align center
font-size 0.8em
color rgba(0, 0, 0, 0.4)
i
margin-right 4px
> .no-history
display block
margin 0
padding 16px
text-align center
font-size 0.8em
color rgba(0, 0, 0, 0.4)
i
margin-right 4px
> .message
// something
> .date
display block
margin 8px 0
text-align center
&:before
content ''
display block
position absolute
height 1px
width 90%
top 16px
left 0
right 0
margin 0 auto
background rgba(0, 0, 0, 0.1)
> span
display inline-block
margin 0
padding 0 16px
//font-weight bold
line-height 32px
color rgba(0, 0, 0, 0.3)
background #fff
> footer
position absolute
z-index 2
bottom 0
width 600px
max-width 100%
margin 0 auto
background rgba(0, 0, 0, 0.1)
padding 0
background rgba(255, 255, 255, 0.95)
background-clip content-box
> span
display inline-block
margin 0
padding 0 16px
//font-weight bold
line-height 32px
color rgba(0, 0, 0, 0.3)
background #fff
> footer
position absolute
z-index 2
bottom 0
width 600px
max-width 100%
margin 0 auto
padding 0
background rgba(255, 255, 255, 0.95)
background-clip content-box
> [ref='notifications']
position absolute
top -48px
width 100%
padding 8px 0
text-align center
> p
display inline-block
margin 0
padding 0 12px 0 28px
cursor pointer
line-height 32px
font-size 12px
color $theme-color-foreground
background $theme-color
border-radius 16px
transition opacity 1s ease
> i
> [ref='notifications']
position absolute
top 0
left 10px
line-height 32px
font-size 16px
top -48px
width 100%
padding 8px 0
text-align center
> .grippie
height 10px
margin-top -10px
background transparent
cursor ns-resize
> p
display inline-block
margin 0
padding 0 12px 0 28px
cursor pointer
line-height 32px
font-size 12px
color $theme-color-foreground
background $theme-color
border-radius 16px
transition opacity 1s ease
&:hover
//background rgba(0, 0, 0, 0.1)
> i
position absolute
top 0
left 10px
line-height 32px
font-size 16px
&:active
//background rgba(0, 0, 0, 0.2)
> .grippie
height 10px
margin-top -10px
background transparent
cursor ns-resize
script.
@mixin \i
@mixin \api
@mixin \messaging-stream
&:hover
//background rgba(0, 0, 0, 0.1)
@user = @opts.user
@init = true
@sending = false
@messages = []
&:active
//background rgba(0, 0, 0, 0.2)
@connection = new @MessagingStreamConnection @I, @user.id
</style>
<script>
@mixin \i
@mixin \api
@mixin \messaging-stream
@on \mount ~>
@connection.event.on \message @on-message
@connection.event.on \read @on-read
@user = @opts.user
@init = true
@sending = false
@messages = []
document.add-event-listener \visibilitychange @on-visibilitychange
@connection = new @MessagingStreamConnection @I, @user.id
@api \messaging/messages do
user_id: @user.id
.then (messages) ~>
@init = false
@messages = messages.reverse!
@update!
@scroll-to-bottom!
.catch (err) ~>
console.error err
@on \mount ~>
@connection.event.on \message @on-message
@connection.event.on \read @on-read
@on \unmount ~>
@connection.event.off \message @on-message
@connection.event.off \read @on-read
@connection.close!
document.add-event-listener \visibilitychange @on-visibilitychange
document.remove-event-listener \visibilitychange @on-visibilitychange
@on \update ~>
@messages.for-each (message) ~>
date = (new Date message.created_at).get-date!
month = (new Date message.created_at).get-month! + 1
message._date = date
message._datetext = month + '月 ' + date + '日'
@on-message = (message) ~>
is-bottom = @is-bottom!
@messages.push message
if message.user_id != @I.id and not document.hidden
@connection.socket.send JSON.stringify do
type: \read
id: message.id
@update!
if is-bottom
# Scroll to bottom
@scroll-to-bottom!
else if message.user_id != @I.id
# Notify
@notify '新しいメッセージがあります'
@on-read = (ids) ~>
if not Array.isArray ids then ids = [ids]
ids.for-each (id) ~>
if (@messages.some (x) ~> x.id == id)
exist = (@messages.map (x) -> x.id).index-of id
@messages[exist].is_read = true
@api \messaging/messages do
user_id: @user.id
.then (messages) ~>
@init = false
@messages = messages.reverse!
@update!
@scroll-to-bottom!
.catch (err) ~>
console.error err
@is-bottom = ~>
current = @refs.stream.scroll-top + @refs.stream.offset-height
max = @refs.stream.scroll-height
current > (max - 32)
@on \unmount ~>
@connection.event.off \message @on-message
@connection.event.off \read @on-read
@connection.close!
@scroll-to-bottom = ~>
@refs.stream.scroll-top = @refs.stream.scroll-height
document.remove-event-listener \visibilitychange @on-visibilitychange
@notify = (message) ~>
n = document.create-element \p
n.inner-HTML = '<i class="fa fa-arrow-circle-down"></i>' + message
n.onclick = ~>
@scroll-to-bottom!
n.parent-node.remove-child n
@refs.notifications.append-child n
@on \update ~>
@messages.for-each (message) ~>
date = (new Date message.created_at).get-date!
month = (new Date message.created_at).get-month! + 1
message._date = date
message._datetext = month + '月 ' + date + '日'
set-timeout ~>
n.style.opacity = 0
set-timeout ~>
n.parent-node.remove-child n
, 1000ms
, 4000ms
@on-message = (message) ~>
is-bottom = @is-bottom!
@on-visibilitychange = ~>
if document.hidden then return
@messages.for-each (message) ~>
if message.user_id != @I.id and not message.is_read
@messages.push message
if message.user_id != @I.id and not document.hidden
@connection.socket.send JSON.stringify do
type: \read
id: message.id
@update!
if is-bottom
# Scroll to bottom
@scroll-to-bottom!
else if message.user_id != @I.id
# Notify
@notify '新しいメッセージがあります'
@on-read = (ids) ~>
if not Array.isArray ids then ids = [ids]
ids.for-each (id) ~>
if (@messages.some (x) ~> x.id == id)
exist = (@messages.map (x) -> x.id).index-of id
@messages[exist].is_read = true
@update!
@is-bottom = ~>
current = @refs.stream.scroll-top + @refs.stream.offset-height
max = @refs.stream.scroll-height
current > (max - 32)
@scroll-to-bottom = ~>
@refs.stream.scroll-top = @refs.stream.scroll-height
@notify = (message) ~>
n = document.create-element \p
n.inner-HTML = '<i class="fa fa-arrow-circle-down"></i>' + message
n.onclick = ~>
@scroll-to-bottom!
n.parent-node.remove-child n
@refs.notifications.append-child n
set-timeout ~>
n.style.opacity = 0
set-timeout ~>
n.parent-node.remove-child n
, 1000ms
, 4000ms
@on-visibilitychange = ~>
if document.hidden then return
@messages.for-each (message) ~>
if message.user_id != @I.id and not message.is_read
@connection.socket.send JSON.stringify do
type: \read
id: message.id
</script>
</mk-messaging-room>

View File

@ -1,29 +1,28 @@
mk-messaging-window
mk-window@window(is-modal={ false }, width={ '500px' }, height={ '560px' })
<yield to="header">
i.fa.fa-comments
| メッセージ
</yield>
<yield to="content">
mk-messaging@index
</yield>
<mk-messaging-window>
<mk-window ref="window" is-modal="{ false }" width="{ '500px' }" height="{ '560px' }"><yield to="header"><i class="fa fa-comments"></i>メッセージ</yield>
<yield to="content">
<mk-messaging ref="index"></mk-messaging></yield>
</mk-window>
<style type="stylus">
:scope
> mk-window
[data-yield='header']
> i
margin-right 4px
style.
> mk-window
[data-yield='header']
> i
margin-right 4px
[data-yield='content']
> mk-messaging
height 100%
[data-yield='content']
> mk-messaging
height 100%
</style>
<script>
@on \mount ~>
@refs.window.on \closed ~>
@unmount!
script.
@on \mount ~>
@refs.window.on \closed ~>
@unmount!
@refs.window.refs.index.on \navigate-user (user) ~>
w = document.body.append-child document.create-element \mk-messaging-room-window
riot.mount w, do
user: user
@refs.window.refs.index.on \navigate-user (user) ~>
w = document.body.append-child document.create-element \mk-messaging-room-window
riot.mount w, do
user: user
</script>
</mk-messaging-window>

View File

@ -1,226 +1,199 @@
mk-notifications
div.notifications(if={ notifications.length != 0 })
virtual(each={ notification, i in notifications })
div.notification(class={ notification.type })
mk-time(time={ notification.created_at })
<mk-notifications>
<div class="notifications" if="{ notifications.length != 0 }">
<virtual each="{ notification, i in notifications }">
<div class="notification { notification.type }">
<mk-time time="{ notification.created_at }"></mk-time>
<div class="main" if="{ notification.type == 'like' }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + notification.user.username }" data-user-preview="{ notification.user.id }"><img class="avatar" src="{ notification.user.avatar_url + '?thumbnail&amp;size=48' }" alt="avatar"/></a>
<div class="text">
<p><i class="fa fa-thumbs-o-up"></i><a href="{ CONFIG.url + '/' + notification.user.username }" data-user-preview="{ notification.user.id }">{ notification.user.name }</a></p><a class="post-ref" href="{ CONFIG.url + '/' + notification.post.user.username + '/' + notification.post.id }">{ getPostSummary(notification.post) }</a>
</div>
</div>
<div class="main" if="{ notification.type == 'repost' }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + notification.post.user.username }" data-user-preview="{ notification.post.user_id }"><img class="avatar" src="{ notification.post.user.avatar_url + '?thumbnail&amp;size=48' }" alt="avatar"/></a>
<div class="text">
<p><i class="fa fa-retweet"></i><a href="{ CONFIG.url + '/' + notification.post.user.username }" data-user-preview="{ notification.post.user_id }">{ notification.post.user.name }</a></p><a class="post-ref" href="{ CONFIG.url + '/' + notification.post.user.username + '/' + notification.post.id }">{ getPostSummary(notification.post.repost) }</a>
</div>
</div>
<div class="main" if="{ notification.type == 'quote' }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + notification.post.user.username }" data-user-preview="{ notification.post.user_id }"><img class="avatar" src="{ notification.post.user.avatar_url + '?thumbnail&amp;size=48' }" alt="avatar"/></a>
<div class="text">
<p><i class="fa fa-quote-left"></i><a href="{ CONFIG.url + '/' + notification.post.user.username }" data-user-preview="{ notification.post.user_id }">{ notification.post.user.name }</a></p><a class="post-preview" href="{ CONFIG.url + '/' + notification.post.user.username + '/' + notification.post.id }">{ getPostSummary(notification.post) }</a>
</div>
</div>
<div class="main" if="{ notification.type == 'follow' }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + notification.user.username }" data-user-preview="{ notification.user.id }"><img class="avatar" src="{ notification.user.avatar_url + '?thumbnail&amp;size=48' }" alt="avatar"/></a>
<div class="text">
<p><i class="fa fa-user-plus"></i><a href="{ CONFIG.url + '/' + notification.user.username }" data-user-preview="{ notification.user.id }">{ notification.user.name }</a></p>
</div>
</div>
<div class="main" if="{ notification.type == 'reply' }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + notification.post.user.username }" data-user-preview="{ notification.post.user_id }"><img class="avatar" src="{ notification.post.user.avatar_url + '?thumbnail&amp;size=48' }" alt="avatar"/></a>
<div class="text">
<p><i class="fa fa-reply"></i><a href="{ CONFIG.url + '/' + notification.post.user.username }" data-user-preview="{ notification.post.user_id }">{ notification.post.user.name }</a></p><a class="post-preview" href="{ CONFIG.url + '/' + notification.post.user.username + '/' + notification.post.id }">{ getPostSummary(notification.post) }</a>
</div>
</div>
<div class="main" if="{ notification.type == 'mention' }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + notification.post.user.username }" data-user-preview="{ notification.post.user_id }"><img class="avatar" src="{ notification.post.user.avatar_url + '?thumbnail&amp;size=48' }" alt="avatar"/></a>
<div class="text">
<p><i class="fa fa-at"></i><a href="{ CONFIG.url + '/' + notification.post.user.username }" data-user-preview="{ notification.post.user_id }">{ notification.post.user.name }</a></p><a class="post-preview" href="{ CONFIG.url + '/' + notification.post.user.username + '/' + notification.post.id }">{ getPostSummary(notification.post) }</a>
</div>
</div>
</div>
<p class="date" if="{ i != notifications.length - 1 &amp;&amp; notification._date != notifications[i + 1]._date }"><span><i class="fa fa-angle-up"></i>{ notification._datetext }</span><span><i class="fa fa-angle-down"></i>{ notifications[i + 1]._datetext }</span></p>
</virtual>
</div>
<p class="empty" if="{ notifications.length == 0 &amp;&amp; !loading }">ありません!</p>
<p class="loading" if="{ loading }"><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます
<mk-ellipsis></mk-ellipsis>
</p>
<style type="stylus">
:scope
display block
div.main(if={ notification.type == 'like' })
a.avatar-anchor(href={ CONFIG.url + '/' + notification.user.username }, data-user-preview={ notification.user.id })
img.avatar(src={ notification.user.avatar_url + '?thumbnail&size=48' }, alt='avatar')
div.text
p
i.fa.fa-thumbs-o-up
a(href={ CONFIG.url + '/' + notification.user.username }, data-user-preview={ notification.user.id }) { notification.user.name }
a.post-ref(href={ CONFIG.url + '/' + notification.post.user.username + '/' + notification.post.id }) { get-post-summary(notification.post) }
div.main(if={ notification.type == 'repost' })
a.avatar-anchor(href={ CONFIG.url + '/' + notification.post.user.username }, data-user-preview={ notification.post.user_id })
img.avatar(src={ notification.post.user.avatar_url + '?thumbnail&size=48' }, alt='avatar')
div.text
p
i.fa.fa-retweet
a(href={ CONFIG.url + '/' + notification.post.user.username }, data-user-preview={ notification.post.user_id }) { notification.post.user.name }
a.post-ref(href={ CONFIG.url + '/' + notification.post.user.username + '/' + notification.post.id }) { get-post-summary(notification.post.repost) }
div.main(if={ notification.type == 'quote' })
a.avatar-anchor(href={ CONFIG.url + '/' + notification.post.user.username }, data-user-preview={ notification.post.user_id })
img.avatar(src={ notification.post.user.avatar_url + '?thumbnail&size=48' }, alt='avatar')
div.text
p
i.fa.fa-quote-left
a(href={ CONFIG.url + '/' + notification.post.user.username }, data-user-preview={ notification.post.user_id }) { notification.post.user.name }
a.post-preview(href={ CONFIG.url + '/' + notification.post.user.username + '/' + notification.post.id }) { get-post-summary(notification.post) }
div.main(if={ notification.type == 'follow' })
a.avatar-anchor(href={ CONFIG.url + '/' + notification.user.username }, data-user-preview={ notification.user.id })
img.avatar(src={ notification.user.avatar_url + '?thumbnail&size=48' }, alt='avatar')
div.text
p
i.fa.fa-user-plus
a(href={ CONFIG.url + '/' + notification.user.username }, data-user-preview={ notification.user.id }) { notification.user.name }
div.main(if={ notification.type == 'reply' })
a.avatar-anchor(href={ CONFIG.url + '/' + notification.post.user.username }, data-user-preview={ notification.post.user_id })
img.avatar(src={ notification.post.user.avatar_url + '?thumbnail&size=48' }, alt='avatar')
div.text
p
i.fa.fa-reply
a(href={ CONFIG.url + '/' + notification.post.user.username }, data-user-preview={ notification.post.user_id }) { notification.post.user.name }
a.post-preview(href={ CONFIG.url + '/' + notification.post.user.username + '/' + notification.post.id }) { get-post-summary(notification.post) }
div.main(if={ notification.type == 'mention' })
a.avatar-anchor(href={ CONFIG.url + '/' + notification.post.user.username }, data-user-preview={ notification.post.user_id })
img.avatar(src={ notification.post.user.avatar_url + '?thumbnail&size=48' }, alt='avatar')
div.text
p
i.fa.fa-at
a(href={ CONFIG.url + '/' + notification.post.user.username }, data-user-preview={ notification.post.user_id }) { notification.post.user.name }
a.post-preview(href={ CONFIG.url + '/' + notification.post.user.username + '/' + notification.post.id }) { get-post-summary(notification.post) }
p.date(if={ i != notifications.length - 1 && notification._date != notifications[i + 1]._date })
span
i.fa.fa-angle-up
| { notification._datetext }
span
i.fa.fa-angle-down
| { notifications[i + 1]._datetext }
p.empty(if={ notifications.length == 0 && !loading })
| ありません!
p.loading(if={ loading })
i.fa.fa-spinner.fa-pulse.fa-fw
| 読み込んでいます
mk-ellipsis
style.
display block
> .notifications
> .notification
margin 0
padding 16px
font-size 0.9em
border-bottom solid 1px rgba(0, 0, 0, 0.05)
&:last-child
border-bottom none
> mk-time
display inline
position absolute
top 16px
right 12px
vertical-align top
color rgba(0, 0, 0, 0.6)
font-size small
> .main
word-wrap break-word
&:after
content ""
display block
clear both
.avatar-anchor
display block
float left
img
min-width 36px
min-height 36px
max-width 36px
max-height 36px
border-radius 6px
.text
float right
width calc(100% - 36px)
padding-left 8px
p
> .notifications
> .notification
margin 0
padding 16px
font-size 0.9em
border-bottom solid 1px rgba(0, 0, 0, 0.05)
&:last-child
border-bottom none
> mk-time
display inline
position absolute
top 16px
right 12px
vertical-align top
color rgba(0, 0, 0, 0.6)
font-size small
> .main
word-wrap break-word
&:after
content ""
display block
clear both
.avatar-anchor
display block
float left
img
min-width 36px
min-height 36px
max-width 36px
max-height 36px
border-radius 6px
.text
float right
width calc(100% - 36px)
padding-left 8px
p
margin 0
i
margin-right 4px
.post-preview
color rgba(0, 0, 0, 0.7)
.post-ref
color rgba(0, 0, 0, 0.7)
&:before, &:after
font-family FontAwesome
font-size 1em
font-weight normal
font-style normal
display inline-block
margin-right 3px
&:before
content "\f10d"
&:after
content "\f10e"
&.like
.text p i
color #FFAC33
&.repost, &.quote
.text p i
color #77B255
&.follow
.text p i
color #53c7ce
&.reply, &.mention
.text p i
color #555
> .date
display block
margin 0
line-height 32px
text-align center
font-size 0.8em
color #aaa
background #fdfdfd
border-bottom solid 1px rgba(0, 0, 0, 0.05)
span
margin 0 16px
i
margin-right 4px
margin-right 8px
.post-preview
color rgba(0, 0, 0, 0.7)
> .empty
margin 0
padding 16px
text-align center
color #aaa
.post-ref
color rgba(0, 0, 0, 0.7)
> .loading
margin 0
padding 16px
text-align center
color #aaa
&:before, &:after
font-family FontAwesome
font-size 1em
font-weight normal
font-style normal
display inline-block
margin-right 3px
> i
margin-right 4px
&:before
content "\f10d"
</style>
<script>
@mixin \api
@mixin \stream
@mixin \user-preview
@mixin \get-post-summary
&:after
content "\f10e"
@notifications = []
@loading = true
&.like
.text p i
color #FFAC33
@on \mount ~>
@api \i/notifications
.then (notifications) ~>
@notifications = notifications
@loading = false
@update!
.catch (err, text-status) ->
console.error err
&.repost, &.quote
.text p i
color #77B255
@stream.on \notification @on-notification
&.follow
.text p i
color #53c7ce
@on \unmount ~>
@stream.off \notification @on-notification
&.reply, &.mention
.text p i
color #555
> .date
display block
margin 0
line-height 32px
text-align center
font-size 0.8em
color #aaa
background #fdfdfd
border-bottom solid 1px rgba(0, 0, 0, 0.05)
span
margin 0 16px
i
margin-right 8px
> .empty
margin 0
padding 16px
text-align center
color #aaa
> .loading
margin 0
padding 16px
text-align center
color #aaa
> i
margin-right 4px
script.
@mixin \api
@mixin \stream
@mixin \user-preview
@mixin \get-post-summary
@notifications = []
@loading = true
@on \mount ~>
@api \i/notifications
.then (notifications) ~>
@notifications = notifications
@loading = false
@on-notification = (notification) ~>
@notifications.unshift notification
@update!
.catch (err, text-status) ->
console.error err
@stream.on \notification @on-notification
@on \unmount ~>
@stream.off \notification @on-notification
@on-notification = (notification) ~>
@notifications.unshift notification
@update!
@on \update ~>
@notifications.for-each (notification) ~>
date = (new Date notification.created_at).get-date!
month = (new Date notification.created_at).get-month! + 1
notification._date = date
notification._datetext = month + '月 ' + date + '日'
@on \update ~>
@notifications.for-each (notification) ~>
date = (new Date notification.created_at).get-date!
month = (new Date notification.created_at).get-month! + 1
notification._date = date
notification._datetext = month + '月 ' + date + '日'
</script>
</mk-notifications>

View File

@ -1,77 +1,80 @@
mk-entrance
main
img(src='/_/resources/title.svg', alt='Misskey')
mk-entrance-signin(if={ mode == 'signin' })
mk-entrance-signup(if={ mode == 'signup' })
div.introduction(if={ mode == 'introduction' })
mk-introduction
button(onclick={ signin }) わかった
mk-forkit
footer
mk-copyright
// ↓ https://github.com/riot/riot/issues/2134 (将来的)
style(data-disable-scope).
<mk-entrance>
<main><img src="/_/resources/title.svg" alt="Misskey"/>
<mk-entrance-signin if="{ mode == 'signin' }"></mk-entrance-signin>
<mk-entrance-signup if="{ mode == 'signup' }"></mk-entrance-signup>
<div class="introduction" if="{ mode == 'introduction' }">
<mk-introduction></mk-introduction>
<button onclick="{ signin }">わかった</button>
</div>
</main>
<mk-forkit></mk-forkit>
<footer>
<mk-copyright></mk-copyright>
</footer>
<!-- ↓ https://github.com/riot/riot/issues/2134 (将来的)-->
<style data-disable-scope="data-disable-scope">
#wait {
right: auto;
left: 15px;
}
style.
display block
height 100%
> main
display block
> img
</style>
<style type="stylus">
:scope
display block
width 160px
height 170px
margin 0 auto
pointer-events none
user-select none
height 100%
> .introduction
max-width 360px
margin 0 auto
color #777
> mk-introduction
padding 32px
background #fff
box-shadow 0 4px 16px rgba(0, 0, 0, 0.2)
> button
> main
display block
margin 16px auto 0 auto
color #666
&:hover
text-decoration underline
> img
display block
width 160px
height 170px
margin 0 auto
pointer-events none
user-select none
> footer
> mk-copyright
margin 0
text-align center
line-height 64px
font-size 10px
color rgba(#000, 0.5)
> .introduction
max-width 360px
margin 0 auto
color #777
script.
@mode = \signin
> mk-introduction
padding 32px
background #fff
box-shadow 0 4px 16px rgba(0, 0, 0, 0.2)
@signup = ~>
@mode = \signup
@update!
> button
display block
margin 16px auto 0 auto
color #666
@signin = ~>
&:hover
text-decoration underline
> footer
> mk-copyright
margin 0
text-align center
line-height 64px
font-size 10px
color rgba(#000, 0.5)
</style>
<script>
@mode = \signin
@update!
@introduction = ~>
@mode = \introduction
@update!
@signup = ~>
@mode = \signup
@update!
@signin = ~>
@mode = \signin
@update!
@introduction = ~>
@mode = \introduction
@update!
</script>
</mk-entrance>

View File

@ -1,128 +1,130 @@
mk-entrance-signin
a.help(href={ CONFIG.urls.about + '/help' }, title='お困りですか?'): i.fa.fa-question
div.form
h1
img(if={ user }, src={ user.avatar_url + '?thumbnail&size=32' })
p { user ? user.name : 'アカウント' }
mk-signin@signin
div.divider: span or
button.signup(onclick={ parent.signup }) 新規登録
a.introduction(onclick={ introduction }) Misskeyについて
style.
display block
width 290px
margin 0 auto
text-align center
&:hover
> .help
opacity 1
> .help
cursor pointer
display block
position absolute
top 0
right 0
z-index 1
margin 0
padding 0
font-size 1.2em
color #999
border none
outline none
background transparent
opacity 0
transition opacity 0.1s ease
&:hover
color #444
&:active
color #222
> i
padding 14px
> .form
padding 10px 28px 16px 28px
background #fff
box-shadow 0px 4px 16px rgba(0, 0, 0, 0.2)
> h1
<mk-entrance-signin><a class="help" href="{ CONFIG.urls.about + '/help' }" title="お困りですか?"><i class="fa fa-question"></i></a>
<div class="form">
<h1><img if="{ user }" src="{ user.avatar_url + '?thumbnail&amp;size=32' }"/>
<p>{ user ? user.name : 'アカウント' }</p>
</h1>
<mk-signin ref="signin"></mk-signin>
</div>
<div class="divider"><span>or</span></div>
<button class="signup" onclick="{ parent.signup }">新規登録</button><a class="introduction" onclick="{ introduction }">Misskeyについて</a>
<style type="stylus">
:scope
display block
margin 0
padding 0
height 54px
line-height 54px
width 290px
margin 0 auto
text-align center
text-transform uppercase
font-size 1em
font-weight bold
color rgba(0, 0, 0, 0.5)
border-bottom solid 1px rgba(0, 0, 0, 0.1)
> p
display inline
&:hover
> .help
opacity 1
> .help
cursor pointer
display block
position absolute
top 0
right 0
z-index 1
margin 0
padding 0
font-size 1.2em
color #999
border none
outline none
background transparent
opacity 0
transition opacity 0.1s ease
> img
&:hover
color #444
&:active
color #222
> i
padding 14px
> .form
padding 10px 28px 16px 28px
background #fff
box-shadow 0px 4px 16px rgba(0, 0, 0, 0.2)
> h1
display block
margin 0
padding 0
height 54px
line-height 54px
text-align center
text-transform uppercase
font-size 1em
font-weight bold
color rgba(0, 0, 0, 0.5)
border-bottom solid 1px rgba(0, 0, 0, 0.1)
> p
display inline
margin 0
padding 0
> img
display inline-block
top 10px
width 32px
height 32px
margin-right 8px
border-radius 100%
&[src='']
display none
> .divider
padding 16px 0
text-align center
&:after
content ""
display block
position absolute
top 50%
width 100%
height 1px
border-top solid 1px rgba(0, 0, 0, 0.1)
> *
z-index 1
padding 0 8px
color rgba(0, 0, 0, 0.5)
background #fdfdfd
> .signup
width 100%
line-height 56px
font-size 1em
color #fff
background $theme-color
border-radius 64px
&:hover
background lighten($theme-color, 5%)
&:active
background darken($theme-color, 5%)
> .introduction
display inline-block
top 10px
width 32px
height 32px
margin-right 8px
border-radius 100%
margin-top 16px
font-size 12px
color #666
&[src='']
display none
</style>
<script>
@on \mount ~>
@refs.signin.on \user (user) ~>
@update do
user: user
> .divider
padding 16px 0
text-align center
&:after
content ""
display block
position absolute
top 50%
width 100%
height 1px
border-top solid 1px rgba(0, 0, 0, 0.1)
> *
z-index 1
padding 0 8px
color rgba(0, 0, 0, 0.5)
background #fdfdfd
> .signup
width 100%
line-height 56px
font-size 1em
color #fff
background $theme-color
border-radius 64px
&:hover
background lighten($theme-color, 5%)
&:active
background darken($theme-color, 5%)
> .introduction
display inline-block
margin-top 16px
font-size 12px
color #666
script.
@on \mount ~>
@refs.signin.on \user (user) ~>
@update do
user: user
@introduction = ~>
@parent.introduction!
@introduction = ~>
@parent.introduction!
</script>
</mk-entrance-signin>

View File

@ -1,44 +1,51 @@
mk-entrance-signup
mk-signup
button.cancel(type='button', onclick={ parent.signin }, title='キャンセル'): i.fa.fa-times
<mk-entrance-signup>
<mk-signup></mk-signup>
<button class="cancel" type="button" onclick="{ parent.signin }" title="キャンセル"><i class="fa fa-times"></i></button>
<style type="stylus">
:scope
display block
width 368px
margin 0 auto
style.
display block
width 368px
margin 0 auto
&:hover
> .cancel
opacity 1
&:hover
> .cancel
opacity 1
> mk-signup
padding 18px 32px 0 32px
background #fff
box-shadow 0px 4px 16px rgba(0, 0, 0, 0.2)
> mk-signup
padding 18px 32px 0 32px
background #fff
box-shadow 0px 4px 16px rgba(0, 0, 0, 0.2)
> .cancel
cursor pointer
display block
position absolute
top 0
right 0
z-index 1
margin 0
padding 0
font-size 1.2em
color #999
border none
outline none
box-shadow none
background transparent
opacity 0
transition opacity 0.1s ease
> .cancel
cursor pointer
display block
position absolute
top 0
right 0
z-index 1
margin 0
padding 0
font-size 1.2em
color #999
border none
outline none
box-shadow none
background transparent
opacity 0
transition opacity 0.1s ease
&:hover
color #555
&:hover
color #555
&:active
color #222
&:active
color #222
> i
padding 14px
> i
padding 14px
</style>
</mk-entrance-signup>

View File

@ -1,51 +1,56 @@
mk-home-page
mk-ui@ui(page={ page }): mk-home@home(mode={ parent.opts.mode })
<mk-home-page>
<mk-ui ref="ui" page="{ page }">
<mk-home ref="home" mode="{ parent.opts.mode }"></mk-home>
</mk-ui>
<style type="stylus">
:scope
display block
style.
display block
background-position center center
background-attachment fixed
background-size cover
background-position center center
background-attachment fixed
background-size cover
</style>
<script>
@mixin \i
@mixin \api
@mixin \ui-progress
@mixin \stream
@mixin \get-post-summary
script.
@mixin \i
@mixin \api
@mixin \ui-progress
@mixin \stream
@mixin \get-post-summary
@unread-count = 0
@unread-count = 0
@page = switch @opts.mode
| \timelie => \home
| \mentions => \mentions
| _ => \home
@page = switch @opts.mode
| \timelie => \home
| \mentions => \mentions
| _ => \home
@on \mount ~>
@refs.ui.refs.home.on \loaded ~>
@Progress.done!
@on \mount ~>
@refs.ui.refs.home.on \loaded ~>
@Progress.done!
document.title = 'Misskey'
if @I.data.wallpaper
@api \drive/files/show do
file_id: @I.data.wallpaper
.then (file) ~>
@root.style.background-image = 'url(' + file.url + ')'
@Progress.start!
@stream.on \post @on-stream-post
document.add-event-listener \visibilitychange @window-on-visibilitychange, false
@on \unmount ~>
@stream.off \post @on-stream-post
document.remove-event-listener \visibilitychange @window-on-visibilitychange
@on-stream-post = (post) ~>
if document.hidden and post.user_id !== @I.id
@unread-count++
document.title = '(' + @unread-count + ') ' + @get-post-summary post
@window-on-visibilitychange = ~>
if !document.hidden
@unread-count = 0
document.title = 'Misskey'
if @I.data.wallpaper
@api \drive/files/show do
file_id: @I.data.wallpaper
.then (file) ~>
@root.style.background-image = 'url(' + file.url + ')'
@Progress.start!
@stream.on \post @on-stream-post
document.add-event-listener \visibilitychange @window-on-visibilitychange, false
@on \unmount ~>
@stream.off \post @on-stream-post
document.remove-event-listener \visibilitychange @window-on-visibilitychange
@on-stream-post = (post) ~>
if document.hidden and post.user_id !== @I.id
@unread-count++
document.title = '(' + @unread-count + ') ' + @get-post-summary post
@window-on-visibilitychange = ~>
if !document.hidden
@unread-count = 0
document.title = 'Misskey'
</script>
</mk-home-page>

View File

@ -1,46 +1,54 @@
mk-not-found
mk-ui
main
h1 Not Found
img(src='/_/resources/rogge.jpg', alt='')
div.mask
style.
display block
main
display block
width 600px
margin 32px auto
> img
<mk-not-found>
<mk-ui>
<main>
<h1>Not Found</h1><img src="/_/resources/rogge.jpg" alt=""/>
<div class="mask"></div>
</main>
</mk-ui>
<style type="stylus">
:scope
display block
width 600px
height 459px
pointer-events none
user-select none
border-radius 16px
box-shadow 0 0 16px rgba(0, 0, 0, 0.1)
> h1
display block
margin 0
padding 0
position absolute
top 260px
left 225px
transform rotate(-12deg)
z-index 2
color #444
font-size 24px
line-height 20px
main
display block
width 600px
margin 32px auto
> .mask
position absolute
top 262px
left 217px
width 126px
height 18px
transform rotate(-12deg)
background #D6D5DA
border-radius 2px 6px 7px 6px
> img
display block
width 600px
height 459px
pointer-events none
user-select none
border-radius 16px
box-shadow 0 0 16px rgba(0, 0, 0, 0.1)
> h1
display block
margin 0
padding 0
position absolute
top 260px
left 225px
transform rotate(-12deg)
z-index 2
color #444
font-size 24px
line-height 20px
> .mask
position absolute
top 262px
left 217px
width 126px
height 18px
transform rotate(-12deg)
background #D6D5DA
border-radius 2px 6px 7px 6px
</style>
</mk-not-found>

View File

@ -1,25 +1,32 @@
mk-post-page
mk-ui@ui: main: mk-post-detail@detail(post={ parent.post })
<mk-post-page>
<mk-ui ref="ui">
<main>
<mk-post-detail ref="detail" post="{ parent.post }"></mk-post-detail>
</main>
</mk-ui>
<style type="stylus">
:scope
display block
style.
display block
main
padding 16px
main
padding 16px
> mk-post-detail
margin 0 auto
> mk-post-detail
margin 0 auto
</style>
<script>
@mixin \ui-progress
script.
@mixin \ui-progress
@post = @opts.post
@post = @opts.post
@on \mount ~>
@Progress.start!
@on \mount ~>
@Progress.start!
@refs.ui.refs.detail.on \post-fetched ~>
@Progress.set 0.5
@refs.ui.refs.detail.on \post-fetched ~>
@Progress.set 0.5
@refs.ui.refs.detail.on \loaded ~>
@Progress.done!
@refs.ui.refs.detail.on \loaded ~>
@Progress.done!
</script>
</mk-post-page>

View File

@ -1,14 +1,19 @@
mk-search-page
mk-ui@ui: mk-search@search(query={ parent.opts.query })
<mk-search-page>
<mk-ui ref="ui">
<mk-search ref="search" query="{ parent.opts.query }"></mk-search>
</mk-ui>
<style type="stylus">
:scope
display block
style.
display block
</style>
<script>
@mixin \ui-progress
script.
@mixin \ui-progress
@on \mount ~>
@Progress.start!
@on \mount ~>
@Progress.start!
@refs.ui.refs.search.on \loaded ~>
@Progress.done!
@refs.ui.refs.search.on \loaded ~>
@Progress.done!
</script>
</mk-search-page>

View File

@ -1,20 +1,25 @@
mk-user-page
mk-ui@ui: mk-user@user(user={ parent.user }, page={ parent.opts.page })
<mk-user-page>
<mk-ui ref="ui">
<mk-user ref="user" user="{ parent.user }" page="{ parent.opts.page }"></mk-user>
</mk-ui>
<style type="stylus">
:scope
display block
style.
display block
</style>
<script>
@mixin \ui-progress
script.
@mixin \ui-progress
@user = @opts.user
@user = @opts.user
@on \mount ~>
@Progress.start!
@on \mount ~>
@Progress.start!
@refs.ui.refs.user.on \user-fetched (user) ~>
@Progress.set 0.5
document.title = user.name + ' | Misskey'
@refs.ui.refs.user.on \user-fetched (user) ~>
@Progress.set 0.5
document.title = user.name + ' | Misskey'
@refs.ui.refs.user.on \loaded ~>
@Progress.done!
@refs.ui.refs.user.on \loaded ~>
@Progress.done!
</script>
</mk-user-page>

View File

@ -1,141 +1,140 @@
mk-post-detail-sub(title={ title })
a.avatar-anchor(href={ CONFIG.url + '/' + post.user.username })
img.avatar(src={ post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar', data-user-preview={ post.user_id })
div.main
header
div.left
a.name(href={ CONFIG.url + '/' + post.user.username }, data-user-preview={ post.user_id })
| { post.user.name }
span.username
| @{ post.user.username }
div.right
a.time(href={ url })
mk-time(time={ post.created_at })
div.body
div.text@text
div.media(if={ post.media })
virtual(each={ file in post.media })
img(src={ file.url + '?thumbnail&size=512' }, alt={ file.name }, title={ file.name })
style.
display block
margin 0
padding 20px 32px
background #fdfdfd
&:after
content ""
display block
clear both
&:hover
> .main > footer > button
color #888
> .avatar-anchor
display block
float left
margin 0 16px 0 0
> .avatar
<mk-post-detail-sub title="{ title }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + post.user.username }"><img class="avatar" src="{ post.user.avatar_url + '?thumbnail&amp;size=64' }" alt="avatar" data-user-preview="{ post.user_id }"/></a>
<div class="main">
<header>
<div class="left"><a class="name" href="{ CONFIG.url + '/' + post.user.username }" data-user-preview="{ post.user_id }">{ post.user.name }</a><span class="username">@{ post.user.username }</span></div>
<div class="right"><a class="time" href="{ url }">
<mk-time time="{ post.created_at }"></mk-time></a></div>
</header>
<div class="body">
<div class="text" ref="text"></div>
<div class="media" if="{ post.media }">
<virtual each="{ file in post.media }"><img src="{ file.url + '?thumbnail&amp;size=512' }" alt="{ file.name }" title="{ file.name }"/></virtual>
</div>
</div>
</div>
<style type="stylus">
:scope
display block
width 44px
height 44px
margin 0
border-radius 4px
vertical-align bottom
> .main
float left
width calc(100% - 60px)
> header
margin-bottom 4px
white-space nowrap
padding 20px 32px
background #fdfdfd
&:after
content ""
display block
clear both
> .left
float left
&:hover
> .main > footer > button
color #888
> .name
display inline
margin 0
padding 0
color #777
font-size 1em
font-weight 700
text-align left
text-decoration none
&:hover
text-decoration underline
> .username
text-align left
margin 0 0 0 8px
color #ccc
> .right
float right
> .time
font-size 0.9em
color #c0c0c0
> .body
> .text
cursor default
> .avatar-anchor
display block
margin 0
padding 0
word-wrap break-word
font-size 1em
color #717171
float left
margin 0 16px 0 0
> mk-url-preview
margin-top 8px
> .media
> img
> .avatar
display block
max-width 100%
width 44px
height 44px
margin 0
border-radius 4px
vertical-align bottom
script.
@mixin \api
@mixin \text
@mixin \date-stringify
@mixin \user-preview
> .main
float left
width calc(100% - 60px)
@post = @opts.post
> header
margin-bottom 4px
white-space nowrap
@url = CONFIG.url + '/' + @post.user.username + '/' + @post.id
&:after
content ""
display block
clear both
@title = @date-stringify @post.created_at
> .left
float left
@on \mount ~>
if @post.text?
tokens = @analyze @post.text
@refs.text.innerHTML = @compile tokens
> .name
display inline
margin 0
padding 0
color #777
font-size 1em
font-weight 700
text-align left
text-decoration none
@refs.text.children.for-each (e) ~>
if e.tag-name == \MK-URL
riot.mount e
&:hover
text-decoration underline
@like = ~>
if @post.is_liked
@api \posts/likes/delete do
post_id: @post.id
.then ~>
@post.is_liked = false
@update!
else
@api \posts/likes/create do
post_id: @post.id
.then ~>
@post.is_liked = true
@update!
> .username
text-align left
margin 0 0 0 8px
color #ccc
> .right
float right
> .time
font-size 0.9em
color #c0c0c0
> .body
> .text
cursor default
display block
margin 0
padding 0
word-wrap break-word
font-size 1em
color #717171
> mk-url-preview
margin-top 8px
> .media
> img
display block
max-width 100%
</style>
<script>
@mixin \api
@mixin \text
@mixin \date-stringify
@mixin \user-preview
@post = @opts.post
@url = CONFIG.url + '/' + @post.user.username + '/' + @post.id
@title = @date-stringify @post.created_at
@on \mount ~>
if @post.text?
tokens = @analyze @post.text
@refs.text.innerHTML = @compile tokens
@refs.text.children.for-each (e) ~>
if e.tag-name == \MK-URL
riot.mount e
@like = ~>
if @post.is_liked
@api \posts/likes/delete do
post_id: @post.id
.then ~>
@post.is_liked = false
@update!
else
@api \posts/likes/create do
post_id: @post.id
.then ~>
@post.is_liked = true
@update!
</script>
</mk-post-detail-sub>

View File

@ -1,415 +1,409 @@
mk-post-detail(title={ title })
div.fetching(if={ fetching })
mk-ellipsis-icon
div.main(if={ !fetching })
button.read-more(if={ p.reply_to && p.reply_to.reply_to_id && context == null }, title='会話をもっと読み込む', onclick={ load-context }, disabled={ loading-context })
i.fa.fa-ellipsis-v(if={ !loading-context })
i.fa.fa-spinner.fa-pulse(if={ loading-context })
div.context
virtual(each={ post in context })
mk-post-detail-sub(post={ post })
div.reply-to(if={ p.reply_to })
mk-post-detail-sub(post={ p.reply_to })
div.repost(if={ is-repost })
p
a.avatar-anchor(href={ CONFIG.url + '/' + post.user.username }, data-user-preview={ post.user_id }): img.avatar(src={ post.user.avatar_url + '?thumbnail&size=32' }, alt='avatar')
i.fa.fa-retweet
a.name(href={ CONFIG.url + '/' + post.user.username }) { post.user.name }
| がRepost
article
a.avatar-anchor(href={ CONFIG.url + '/' + p.user.username })
img.avatar(src={ p.user.avatar_url + '?thumbnail&size=64' }, alt='avatar', data-user-preview={ p.user.id })
header
a.name(href={ CONFIG.url + '/' + p.user.username }, data-user-preview={ p.user.id })
| { p.user.name }
span.username
| @{ p.user.username }
a.time(href={ url })
mk-time(time={ p.created_at })
div.body
div.text@text
div.media(if={ p.media })
virtual(each={ file in p.media })
img(src={ file.url + '?thumbnail&size=512' }, alt={ file.name }, title={ file.name })
footer
button(onclick={ reply }, title='返信')
i.fa.fa-reply
p.count(if={ p.replies_count > 0 }) { p.replies_count }
button(onclick={ repost }, title='Repost')
i.fa.fa-retweet
p.count(if={ p.repost_count > 0 }) { p.repost_count }
button(class={ liked: p.is_liked }, onclick={ like }, title='善哉')
i.fa.fa-thumbs-o-up
p.count(if={ p.likes_count > 0 }) { p.likes_count }
button(onclick={ NotImplementedException }): i.fa.fa-ellipsis-h
div.reposts-and-likes
div.reposts(if={ reposts && reposts.length > 0 })
header
a { p.repost_count }
p Repost
ol.users
li.user(each={ reposts })
a.avatar-anchor(href={ CONFIG.url + '/' + user.username }, title={ user.name }, data-user-preview={ user.id })
img.avatar(src={ user.avatar_url + '?thumbnail&size=32' }, alt='')
div.likes(if={ likes && likes.length > 0 })
header
a { p.likes_count }
p いいね
ol.users
li.user(each={ likes })
a.avatar-anchor(href={ CONFIG.url + '/' + username }, title={ name }, data-user-preview={ id })
img.avatar(src={ avatar_url + '?thumbnail&size=32' }, alt='')
div.replies
virtual(each={ post in replies })
mk-post-detail-sub(post={ post })
style.
display block
margin 0
padding 0
width 640px
overflow hidden
background #fff
border solid 1px rgba(0, 0, 0, 0.1)
border-radius 8px
> .fetching
padding 64px 0
> .main
> .read-more
<mk-post-detail title="{ title }">
<div class="fetching" if="{ fetching }">
<mk-ellipsis-icon></mk-ellipsis-icon>
</div>
<div class="main" if="{ !fetching }">
<button class="read-more" if="{ p.reply_to &amp;&amp; p.reply_to.reply_to_id &amp;&amp; context == null }" title="会話をもっと読み込む" onclick="{ loadContext }" disabled="{ loadingContext }"><i class="fa fa-ellipsis-v" if="{ !loadingContext }"></i><i class="fa fa-spinner fa-pulse" if="{ loadingContext }"></i></button>
<div class="context">
<virtual each="{ post in context }">
<mk-post-detail-sub post="{ post }"></mk-post-detail-sub>
</virtual>
</div>
<div class="reply-to" if="{ p.reply_to }">
<mk-post-detail-sub post="{ p.reply_to }"></mk-post-detail-sub>
</div>
<div class="repost" if="{ isRepost }">
<p><a class="avatar-anchor" href="{ CONFIG.url + '/' + post.user.username }" data-user-preview="{ post.user_id }"><img class="avatar" src="{ post.user.avatar_url + '?thumbnail&amp;size=32' }" alt="avatar"/></a><i class="fa fa-retweet"></i><a class="name" href="{ CONFIG.url + '/' + post.user.username }">{ post.user.name }</a>がRepost</p>
</div>
<article><a class="avatar-anchor" href="{ CONFIG.url + '/' + p.user.username }"><img class="avatar" src="{ p.user.avatar_url + '?thumbnail&amp;size=64' }" alt="avatar" data-user-preview="{ p.user.id }"/></a>
<header><a class="name" href="{ CONFIG.url + '/' + p.user.username }" data-user-preview="{ p.user.id }">{ p.user.name }</a><span class="username">@{ p.user.username }</span><a class="time" href="{ url }">
<mk-time time="{ p.created_at }"></mk-time></a></header>
<div class="body">
<div class="text" ref="text"></div>
<div class="media" if="{ p.media }">
<virtual each="{ file in p.media }"><img src="{ file.url + '?thumbnail&amp;size=512' }" alt="{ file.name }" title="{ file.name }"/></virtual>
</div>
</div>
<footer>
<button onclick="{ reply }" title="返信"><i class="fa fa-reply"></i>
<p class="count" if="{ p.replies_count &gt; 0 }">{ p.replies_count }</p>
</button>
<button onclick="{ repost }" title="Repost"><i class="fa fa-retweet"></i>
<p class="count" if="{ p.repost_count &gt; 0 }">{ p.repost_count }</p>
</button>
<button class="{ liked: p.is_liked }" onclick="{ like }" title="善哉"><i class="fa fa-thumbs-o-up"></i>
<p class="count" if="{ p.likes_count &gt; 0 }">{ p.likes_count }</p>
</button>
<button onclick="{ NotImplementedException }"><i class="fa fa-ellipsis-h"></i></button>
</footer>
<div class="reposts-and-likes">
<div class="reposts" if="{ reposts &amp;&amp; reposts.length &gt; 0 }">
<header><a>{ p.repost_count }</a>
<p>Repost</p>
</header>
<ol class="users">
<li class="user" each="{ reposts }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + user.username }" title="{ user.name }" data-user-preview="{ user.id }"><img class="avatar" src="{ user.avatar_url + '?thumbnail&amp;size=32' }" alt=""/></a></li>
</ol>
</div>
<div class="likes" if="{ likes &amp;&amp; likes.length &gt; 0 }">
<header><a>{ p.likes_count }</a>
<p>いいね</p>
</header>
<ol class="users">
<li class="user" each="{ likes }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + username }" title="{ name }" data-user-preview="{ id }"><img class="avatar" src="{ avatar_url + '?thumbnail&amp;size=32' }" alt=""/></a></li>
</ol>
</div>
</div>
</article>
<div class="replies">
<virtual each="{ post in replies }">
<mk-post-detail-sub post="{ post }"></mk-post-detail-sub>
</virtual>
</div>
</div>
<style type="stylus">
:scope
display block
margin 0
padding 10px 0
width 100%
font-size 1em
text-align center
color #999
cursor pointer
background #fafafa
outline none
border none
border-bottom solid 1px #eef0f2
border-radius 6px 6px 0 0
padding 0
width 640px
overflow hidden
background #fff
border solid 1px rgba(0, 0, 0, 0.1)
border-radius 8px
&:hover
background #f6f6f6
> .fetching
padding 64px 0
&:active
background #f0f0f0
> .main
&:disabled
color #ccc
> .context
> *
border-bottom 1px solid #eef0f2
> .repost
color #9dbb00
background linear-gradient(to bottom, #edfde2 0%, #fff 100%)
> p
margin 0
padding 16px 32px
.avatar-anchor
display inline-block
.avatar
vertical-align bottom
min-width 28px
min-height 28px
max-width 28px
max-height 28px
margin 0 8px 0 0
border-radius 6px
i
margin-right 4px
.name
font-weight bold
& + article
padding-top 8px
> .reply-to
border-bottom 1px solid #eef0f2
> article
padding 28px 32px 18px 32px
&:after
content ""
display block
clear both
&:hover
> .main > footer > button
color #888
> .avatar-anchor
display block
width 60px
height 60px
> .avatar
> .read-more
display block
width 60px
height 60px
margin 0
border-radius 8px
vertical-align bottom
> header
position absolute
top 28px
left 108px
width calc(100% - 108px)
> .name
display inline-block
margin 0
line-height 24px
color #777
font-size 18px
font-weight 700
text-align left
text-decoration none
&:hover
text-decoration underline
> .username
display block
text-align left
margin 0
color #ccc
> .time
position absolute
top 0
right 32px
padding 10px 0
width 100%
font-size 1em
color #c0c0c0
> .body
padding 8px 0
> .text
cursor default
display block
margin 0
padding 0
word-wrap break-word
font-size 1.5em
color #717171
> mk-url-preview
margin-top 8px
> .media
> img
display block
max-width 100%
> footer
font-size 1.2em
> button
margin 0 28px 0 0
padding 8px
background transparent
border none
font-size 1em
color #ddd
text-align center
color #999
cursor pointer
background #fafafa
outline none
border none
border-bottom solid 1px #eef0f2
border-radius 6px 6px 0 0
&:hover
color #666
background #f6f6f6
> .count
display inline
margin 0 0 0 8px
color #999
&:active
background #f0f0f0
&.liked
color $theme-color
&:disabled
color #ccc
> .reposts-and-likes
display flex
justify-content center
padding 0
margin 16px 0
> .context
> *
border-bottom 1px solid #eef0f2
&:empty
display none
> .repost
color #9dbb00
background linear-gradient(to bottom, #edfde2 0%, #fff 100%)
> .reposts
> .likes
display flex
flex 1 1
padding 0
border-top solid 1px #F2EFEE
> p
margin 0
padding 16px 32px
.avatar-anchor
display inline-block
.avatar
vertical-align bottom
min-width 28px
min-height 28px
max-width 28px
max-height 28px
margin 0 8px 0 0
border-radius 6px
i
margin-right 4px
.name
font-weight bold
& + article
padding-top 8px
> .reply-to
border-bottom 1px solid #eef0f2
> article
padding 28px 32px 18px 32px
&:after
content ""
display block
clear both
&:hover
> .main > footer > button
color #888
> .avatar-anchor
display block
width 60px
height 60px
> .avatar
display block
width 60px
height 60px
margin 0
border-radius 8px
vertical-align bottom
> header
flex 1 1 80px
max-width 80px
padding 8px 5px 0px 10px
position absolute
top 28px
left 108px
width calc(100% - 108px)
> a
> .name
display inline-block
margin 0
line-height 24px
color #777
font-size 18px
font-weight 700
text-align left
text-decoration none
&:hover
text-decoration underline
> .username
display block
font-size 1.5em
line-height 1.4em
text-align left
margin 0
color #ccc
> p
> .time
position absolute
top 0
right 32px
font-size 1em
color #c0c0c0
> .body
padding 8px 0
> .text
cursor default
display block
margin 0
font-size 0.7em
line-height 1em
font-weight normal
color #a0a2a5
> .users
display block
flex 1 1
margin 0
padding 10px 10px 10px 5px
list-style none
> .user
display block
float left
margin 4px
padding 0
word-wrap break-word
font-size 1.5em
color #717171
> .avatar-anchor
display:block
> mk-url-preview
margin-top 8px
> .avatar
vertical-align bottom
width 24px
height 24px
border-radius 4px
> .media
> img
display block
max-width 100%
> .reposts + .likes
margin-left 16px
> footer
font-size 1.2em
> .replies
> *
border-top 1px solid #eef0f2
> button
margin 0 28px 0 0
padding 8px
background transparent
border none
font-size 1em
color #ddd
cursor pointer
script.
@mixin \api
@mixin \text
@mixin \user-preview
@mixin \date-stringify
@mixin \NotImplementedException
&:hover
color #666
@fetching = true
@loading-context = false
@content = null
@post = null
> .count
display inline
margin 0 0 0 8px
color #999
@on \mount ~>
&.liked
color $theme-color
@api \posts/show do
post_id: @opts.post
.then (post) ~>
@fetching = false
@post = post
@trigger \loaded
> .reposts-and-likes
display flex
justify-content center
padding 0
margin 16px 0
@is-repost = @post.repost?
@p = if @is-repost then @post.repost else @post
&:empty
display none
@title = @date-stringify @p.created_at
> .reposts
> .likes
display flex
flex 1 1
padding 0
border-top solid 1px #F2EFEE
@update!
> header
flex 1 1 80px
max-width 80px
padding 8px 5px 0px 10px
if @p.text?
tokens = @analyze @p.text
@refs.text.innerHTML = @compile tokens
> a
display block
font-size 1.5em
line-height 1.4em
@refs.text.children.for-each (e) ~>
if e.tag-name == \MK-URL
riot.mount e
> p
display block
margin 0
font-size 0.7em
line-height 1em
font-weight normal
color #a0a2a5
# URLをプレビュー
tokens
.filter (t) -> t.type == \link
.map (t) ~>
@preview = @refs.text.append-child document.create-element \mk-url-preview
riot.mount @preview, do
url: t.content
> .users
display block
flex 1 1
margin 0
padding 10px 10px 10px 5px
list-style none
> .user
display block
float left
margin 4px
padding 0
> .avatar-anchor
display:block
> .avatar
vertical-align bottom
width 24px
height 24px
border-radius 4px
> .reposts + .likes
margin-left 16px
> .replies
> *
border-top 1px solid #eef0f2
</style>
<script>
@mixin \api
@mixin \text
@mixin \user-preview
@mixin \date-stringify
@mixin \NotImplementedException
@fetching = true
@loading-context = false
@content = null
@post = null
@on \mount ~>
@api \posts/show do
post_id: @opts.post
.then (post) ~>
@fetching = false
@post = post
@trigger \loaded
@is-repost = @post.repost?
@p = if @is-repost then @post.repost else @post
@title = @date-stringify @p.created_at
# Get likes
@api \posts/likes do
post_id: @p.id
limit: 8
.then (likes) ~>
@likes = likes
@update!
# Get reposts
@api \posts/reposts do
post_id: @p.id
limit: 8
.then (reposts) ~>
@reposts = reposts
if @p.text?
tokens = @analyze @p.text
@refs.text.innerHTML = @compile tokens
@refs.text.children.for-each (e) ~>
if e.tag-name == \MK-URL
riot.mount e
# URLをプレビュー
tokens
.filter (t) -> t.type == \link
.map (t) ~>
@preview = @refs.text.append-child document.create-element \mk-url-preview
riot.mount @preview, do
url: t.content
# Get likes
@api \posts/likes do
post_id: @p.id
limit: 8
.then (likes) ~>
@likes = likes
@update!
# Get reposts
@api \posts/reposts do
post_id: @p.id
limit: 8
.then (reposts) ~>
@reposts = reposts
@update!
# Get replies
@api \posts/replies do
post_id: @p.id
limit: 8
.then (replies) ~>
@replies = replies
@update!
@update!
# Get replies
@api \posts/replies do
post_id: @p.id
limit: 8
.then (replies) ~>
@replies = replies
@reply = ~>
form = document.body.append-child document.create-element \mk-post-form-window
riot.mount form, do
reply: @p
@repost = ~>
form = document.body.append-child document.create-element \mk-repost-form-window
riot.mount form, do
post: @p
@like = ~>
if @p.is_liked
@api \posts/likes/delete do
post_id: @p.id
.then ~>
@p.is_liked = false
@update!
else
@api \posts/likes/create do
post_id: @p.id
.then ~>
@p.is_liked = true
@update!
@load-context = ~>
@loading-context = true
# Get context
@api \posts/context do
post_id: @p.reply_to_id
.then (context) ~>
@context = context.reverse!
@loading-context = false
@update!
@update!
@reply = ~>
form = document.body.append-child document.create-element \mk-post-form-window
riot.mount form, do
reply: @p
@repost = ~>
form = document.body.append-child document.create-element \mk-repost-form-window
riot.mount form, do
post: @p
@like = ~>
if @p.is_liked
@api \posts/likes/delete do
post_id: @p.id
.then ~>
@p.is_liked = false
@update!
else
@api \posts/likes/create do
post_id: @p.id
.then ~>
@p.is_liked = true
@update!
@load-context = ~>
@loading-context = true
# Get context
@api \posts/context do
post_id: @p.reply_to_id
.then (context) ~>
@context = context.reverse!
@loading-context = false
@update!
</script>
</mk-post-detail>

View File

@ -1,60 +1,55 @@
mk-post-form-window
<mk-post-form-window>
<mk-window ref="window" is-modal="{ true }" colored="{ true }"><yield to="header"><span if="{ !parent.opts.reply }">新規投稿</span><span if="{ parent.opts.reply }">返信</span><span class="files" if="{ parent.files.length != 0 }">添付: { parent.files.length }ファイル</span><span class="uploading-files" if="{ parent.uploadingFiles.length != 0 }">{ parent.uploadingFiles.length }個のファイルをアップロード中
<mk-ellipsis></mk-ellipsis></span></yield>
<yield to="content">
<div class="ref" if="{ parent.opts.reply }">
<mk-post-preview post="{ parent.opts.reply }"></mk-post-preview>
</div>
<div class="body">
<mk-post-form ref="form" reply="{ parent.opts.reply }"></mk-post-form>
</div></yield>
</mk-window>
<style type="stylus">
:scope
> mk-window
mk-window@window(is-modal={ true }, colored={ true })
[data-yield='header']
> .files
> .uploading-files
margin-left 8px
opacity 0.8
<yield to="header">
span(if={ !parent.opts.reply }) 新規投稿
span(if={ parent.opts.reply }) 返信
span.files(if={ parent.files.length != 0 }) 添付: { parent.files.length }ファイル
span.uploading-files(if={ parent.uploading-files.length != 0 })
| { parent.uploading-files.length }個のファイルをアップロード中
mk-ellipsis
</yield>
&:before
content '('
<yield to="content">
div.ref(if={ parent.opts.reply })
mk-post-preview(post={ parent.opts.reply })
div.body
mk-post-form@form(reply={ parent.opts.reply })
</yield>
&:after
content ')'
style.
> mk-window
[data-yield='content']
> .ref
> mk-post-preview
margin 16px 22px
[data-yield='header']
> .files
> .uploading-files
margin-left 8px
opacity 0.8
</style>
<script>
@uploading-files = []
@files = []
&:before
content '('
@on \mount ~>
@refs.window.refs.form.focus!
&:after
content ')'
@refs.window.on \closed ~>
@unmount!
[data-yield='content']
> .ref
> mk-post-preview
margin 16px 22px
@refs.window.refs.form.on \post ~>
@refs.window.close!
script.
@uploading-files = []
@files = []
@refs.window.refs.form.on \change-uploading-files (files) ~>
@uploading-files = files
@update!
@on \mount ~>
@refs.window.refs.form.focus!
@refs.window.on \closed ~>
@unmount!
@refs.window.refs.form.on \post ~>
@refs.window.close!
@refs.window.refs.form.on \change-uploading-files (files) ~>
@uploading-files = files
@update!
@refs.window.refs.form.on \change-files (files) ~>
@files = files
@update!
@refs.window.refs.form.on \change-files (files) ~>
@files = files
@update!
</script>
</mk-post-form-window>

View File

@ -1,430 +1,434 @@
mk-post-form(ondragover={ ondragover }, ondragenter={ ondragenter }, ondragleave={ ondragleave }, ondrop={ ondrop })
textarea@text(disabled={ wait }, class={ withfiles: files.length != 0 }, oninput={ update }, onkeydown={ onkeydown }, onpaste={ onpaste }, placeholder={ opts.reply ? 'この投稿への返信...' : 'いまどうしてる?' })
div.attaches(if={ files.length != 0 })
ul.files@attaches
li.file(each={ files })
div.img(style='background-image: url({ url + "?thumbnail&size=64" })', title={ name })
img.remove(onclick={ _remove }, src='/_/resources/desktop/remove.png', title='添付取り消し', alt='')
li.add(if={ files.length < 4 }, title='PCからファイルを添付', onclick={ select-file }): i.fa.fa-plus
p.remain
| 残り{ 4 - files.length }
mk-uploader@uploader
button@upload(title='PCからファイルを添付', onclick={ select-file }): i.fa.fa-upload
button@drive(title='ドライブからファイルを添付', onclick={ select-file-from-drive }): i.fa.fa-cloud
p.text-count(class={ over: refs.text.value.length > 300 }) のこり{ 300 - refs.text.value.length }文字
button@submit(class={ wait: wait }, disabled={ wait || (refs.text.value.length == 0 && files.length == 0) }, onclick={ post })
| { wait ? '投稿中' : opts.reply ? '返信' : '投稿' }
mk-ellipsis(if={ wait })
input@file(type='file', accept='image/*', multiple, tabindex='-1', onchange={ change-file })
div.dropzone(if={ draghover })
style.
display block
padding 16px
background lighten($theme-color, 95%)
&:after
content ""
display block
clear both
> .attaches
margin 0
padding 0
background lighten($theme-color, 98%)
border solid 1px rgba($theme-color, 0.1)
border-top none
border-radius 0 0 4px 4px
transition border-color .3s ease
> .remain
<mk-post-form ondragover="{ ondragover }" ondragenter="{ ondragenter }" ondragleave="{ ondragleave }" ondrop="{ ondrop }">
<textarea class="{ withfiles: files.length != 0 }" ref="text" disabled="{ wait }" oninput="{ update }" onkeydown="{ onkeydown }" onpaste="{ onpaste }" placeholder="{ opts.reply ? 'この投稿への返信...' : 'いまどうしてる?' }"></textarea>
<div class="attaches" if="{ files.length != 0 }">
<ul class="files" ref="attaches">
<li class="file" each="{ files }">
<div class="img" style="background-image: url({ url + &quot;?thumbnail&amp;size=64&quot; })" title="{ name }"></div><img class="remove" onclick="{ _remove }" src="/_/resources/desktop/remove.png" title="添付取り消し" alt=""/>
</li>
<li class="add" if="{ files.length &lt; 4 }" title="PCからファイルを添付" onclick="{ selectFile }"><i class="fa fa-plus"></i></li>
</ul>
<p class="remain">残り{ 4 - files.length }</p>
</div>
<mk-uploader ref="uploader"></mk-uploader>
<button ref="upload" title="PCからファイルを添付" onclick="{ selectFile }"><i class="fa fa-upload"></i></button>
<button ref="drive" title="ドライブからファイルを添付" onclick="{ selectFileFromDrive }"><i class="fa fa-cloud"></i></button>
<p class="text-count { over: refs.text.value.length &gt; 300 }">のこり{ 300 - refs.text.value.length }文字</p>
<button class="{ wait: wait }" ref="submit" disabled="{ wait || (refs.text.value.length == 0 &amp;&amp; files.length == 0) }" onclick="{ post }">{ wait ? '投稿中' : opts.reply ? '返信' : '投稿' }
<mk-ellipsis if="{ wait }"></mk-ellipsis>
</button>
<input ref="file" type="file" accept="image/*" multiple="multiple" tabindex="-1" onchange="{ changeFile }"/>
<div class="dropzone" if="{ draghover }"></div>
<style type="stylus">
:scope
display block
position absolute
top 8px
right 8px
margin 0
padding 0
color rgba($theme-color, 0.4)
> .files
display block
margin 0
padding 4px
list-style none
padding 16px
background lighten($theme-color, 95%)
&:after
content ""
display block
clear both
> .file
display block
float left
margin 4px
> .attaches
margin 0
padding 0
cursor move
background lighten($theme-color, 98%)
border solid 1px rgba($theme-color, 0.1)
border-top none
border-radius 0 0 4px 4px
transition border-color .3s ease
&:hover > .remove
> .remain
display block
> .img
width 64px
height 64px
background-size cover
background-position center center
> .remove
display none
position absolute
top -6px
right -6px
width 16px
height 16px
cursor pointer
top 8px
right 8px
margin 0
padding 0
color rgba($theme-color, 0.4)
> .add
> .files
display block
margin 0
padding 4px
list-style none
&:after
content ""
display block
clear both
> .file
display block
float left
margin 4px
padding 0
cursor move
&:hover > .remove
display block
> .img
width 64px
height 64px
background-size cover
background-position center center
> .remove
display none
position absolute
top -6px
right -6px
width 16px
height 16px
cursor pointer
> .add
display block
float left
margin 4px
padding 0
border dashed 2px rgba($theme-color, 0.2)
cursor pointer
&:hover
border-color rgba($theme-color, 0.3)
> i
color rgba($theme-color, 0.4)
> i
display block
width 60px
height 60px
line-height 60px
text-align center
font-size 1.2em
color rgba($theme-color, 0.2)
> mk-uploader
margin 8px 0 0 0
padding 8px
border solid 1px rgba($theme-color, 0.2)
border-radius 4px
[ref='file']
display none
[ref='text']
display block
float left
margin 4px
padding 0
border dashed 2px rgba($theme-color, 0.2)
cursor pointer
padding 12px
margin 0
width 100%
max-width 100%
min-width 100%
min-height calc(16px + 12px + 12px)
font-size 16px
color #333
background #fff
outline none
border solid 1px rgba($theme-color, 0.1)
border-radius 4px
transition border-color .3s ease
&:hover
border-color rgba($theme-color, 0.2)
transition border-color .1s ease
&:focus
color $theme-color
border-color rgba($theme-color, 0.5)
transition border-color 0s ease
&:disabled
opacity 0.5
&::-webkit-input-placeholder
color rgba($theme-color, 0.3)
&.withfiles
border-bottom solid 1px rgba($theme-color, 0.1) !important
border-radius 4px 4px 0 0
&:hover + .attaches
border-color rgba($theme-color, 0.2)
transition border-color .1s ease
&:focus + .attaches
border-color rgba($theme-color, 0.5)
transition border-color 0s ease
.text-count
pointer-events none
display block
position absolute
bottom 16px
right 138px
margin 0
line-height 40px
color rgba($theme-color, 0.5)
&.over
color #ec3828
[ref='submit']
display block
position absolute
bottom 16px
right 16px
cursor pointer
padding 0
margin 0
width 110px
height 40px
font-size 1em
color $theme-color-foreground
background linear-gradient(to bottom, lighten($theme-color, 25%) 0%, lighten($theme-color, 10%) 100%)
outline none
border solid 1px lighten($theme-color, 15%)
border-radius 4px
&: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
&: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
&.wait
background linear-gradient(
45deg,
darken($theme-color, 10%) 25%,
$theme-color 25%,
$theme-color 50%,
darken($theme-color, 10%) 50%,
darken($theme-color, 10%) 75%,
$theme-color 75%,
$theme-color
)
background-size 32px 32px
animation stripe-bg 1.5s linear infinite
opacity 0.7
cursor wait
@keyframes stripe-bg
from {background-position: 0 0;}
to {background-position: -64px 32px;}
[ref='upload']
[ref='drive']
display inline-block
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)
> i
color rgba($theme-color, 0.4)
&:active
color rgba($theme-color, 0.6)
background linear-gradient(to bottom, lighten($theme-color, 80%) 0%, lighten($theme-color, 90%) 100%)
border-color rgba($theme-color, 0.5)
box-shadow 0 2px 4px rgba(0, 0, 0, 0.15) inset
> i
display block
width 60px
height 60px
line-height 60px
text-align center
font-size 1.2em
color rgba($theme-color, 0.2)
&: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
> mk-uploader
margin 8px 0 0 0
padding 8px
border solid 1px rgba($theme-color, 0.2)
border-radius 4px
[ref='file']
display none
[ref='text']
display block
padding 12px
margin 0
width 100%
max-width 100%
min-width 100%
min-height calc(16px + 12px + 12px)
font-size 16px
color #333
background #fff
outline none
border solid 1px rgba($theme-color, 0.1)
border-radius 4px
transition border-color .3s ease
&:hover
border-color rgba($theme-color, 0.2)
transition border-color .1s ease
&:focus
color $theme-color
border-color rgba($theme-color, 0.5)
transition border-color 0s ease
&:disabled
opacity 0.5
&::-webkit-input-placeholder
color rgba($theme-color, 0.3)
&.withfiles
border-bottom solid 1px rgba($theme-color, 0.1) !important
border-radius 4px 4px 0 0
&:hover + .attaches
border-color rgba($theme-color, 0.2)
transition border-color .1s ease
&:focus + .attaches
border-color rgba($theme-color, 0.5)
transition border-color 0s ease
.text-count
pointer-events none
display block
position absolute
bottom 16px
right 138px
margin 0
line-height 40px
color rgba($theme-color, 0.5)
&.over
color #ec3828
[ref='submit']
display block
position absolute
bottom 16px
right 16px
cursor pointer
padding 0
margin 0
width 110px
height 40px
font-size 1em
color $theme-color-foreground
background linear-gradient(to bottom, lighten($theme-color, 25%) 0%, lighten($theme-color, 10%) 100%)
outline none
border solid 1px lighten($theme-color, 15%)
border-radius 4px
&: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
&:focus
&:after
content ""
pointer-events none
> .dropzone
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
&.wait
background linear-gradient(
45deg,
darken($theme-color, 10%) 25%,
$theme-color 25%,
$theme-color 50%,
darken($theme-color, 10%) 50%,
darken($theme-color, 10%) 75%,
$theme-color 75%,
$theme-color
)
background-size 32px 32px
animation stripe-bg 1.5s linear infinite
opacity 0.7
cursor wait
@keyframes stripe-bg
from {background-position: 0 0;}
to {background-position: -64px 32px;}
[ref='upload']
[ref='drive']
display inline-block
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 linear-gradient(to bottom, lighten($theme-color, 80%) 0%, lighten($theme-color, 90%) 100%)
border-color rgba($theme-color, 0.5)
box-shadow 0 2px 4px rgba(0, 0, 0, 0.15) inset
&:focus
&:after
content ""
left 0
top 0
width 100%
height 100%
border dashed 2px rgba($theme-color, 0.5)
pointer-events none
position absolute
top -5px
right -5px
bottom -5px
left -5px
border 2px solid rgba($theme-color, 0.3)
border-radius 8px
> .dropzone
position absolute
left 0
top 0
width 100%
height 100%
border dashed 2px rgba($theme-color, 0.5)
pointer-events none
</style>
<script>
@mixin \api
@mixin \notify
@mixin \autocomplete
@mixin \sortable
script.
@mixin \api
@mixin \notify
@mixin \autocomplete
@mixin \sortable
@wait = false
@uploadings = []
@files = []
@autocomplete = null
@in-reply-to-post = @opts.reply
# https://github.com/riot/riot/issues/2080
if @in-reply-to-post == '' then @in-reply-to-post = null
@on \mount ~>
@refs.uploader.on \uploaded (file) ~>
@add-file file
@refs.uploader.on \change-uploads (uploads) ~>
@trigger \change-uploading-files uploads
@autocomplete = new @Autocomplete @refs.text
@autocomplete.attach!
@on \unmount ~>
@autocomplete.detach!
@focus = ~>
@refs.text.focus!
@clear = ~>
@refs.text.value = ''
@wait = false
@uploadings = []
@files = []
@trigger \change-files
@update!
@autocomplete = null
@ondragover = (e) ~>
e.stop-propagation!
@draghover = true
# ドラッグされてきたものがファイルだったら
if e.data-transfer.effect-allowed == \all
e.data-transfer.drop-effect = \copy
else
e.data-transfer.drop-effect = \move
return false
@in-reply-to-post = @opts.reply
@ondragenter = (e) ~>
@draghover = true
# https://github.com/riot/riot/issues/2080
if @in-reply-to-post == '' then @in-reply-to-post = null
@ondragleave = (e) ~>
@draghover = false
@on \mount ~>
@refs.uploader.on \uploaded (file) ~>
@add-file file
@ondrop = (e) ~>
e.prevent-default!
e.stop-propagation!
@draghover = false
@refs.uploader.on \change-uploads (uploads) ~>
@trigger \change-uploading-files uploads
# ファイルだったら
if e.data-transfer.files.length > 0
Array.prototype.for-each.call e.data-transfer.files, (file) ~>
@autocomplete = new @Autocomplete @refs.text
@autocomplete.attach!
@on \unmount ~>
@autocomplete.detach!
@focus = ~>
@refs.text.focus!
@clear = ~>
@refs.text.value = ''
@files = []
@trigger \change-files
@update!
@ondragover = (e) ~>
e.stop-propagation!
@draghover = true
# ドラッグされてきたものがファイルだったら
if e.data-transfer.effect-allowed == \all
e.data-transfer.drop-effect = \copy
else
e.data-transfer.drop-effect = \move
return false
@ondragenter = (e) ~>
@draghover = true
@ondragleave = (e) ~>
@draghover = false
@ondrop = (e) ~>
e.prevent-default!
e.stop-propagation!
@draghover = false
# ファイルだったら
if e.data-transfer.files.length > 0
Array.prototype.for-each.call e.data-transfer.files, (file) ~>
@upload file
return false
# データ取得
data = e.data-transfer.get-data 'text'
if !data?
return false
try
# パース
obj = JSON.parse data
# (ドライブの)ファイルだったら
if obj.type == \file
@add-file obj.file
catch
# ignore
return false
@onkeydown = (e) ~>
if (e.which == 10 || e.which == 13) && (e.ctrl-key || e.meta-key)
@post!
@onpaste = (e) ~>
data = e.clipboard-data
items = data.items
for i from 0 to items.length - 1
item = items[i]
switch (item.kind)
| \file =>
@upload item.get-as-file!
@select-file = ~>
@refs.file.click!
@select-file-from-drive = ~>
browser = document.body.append-child document.create-element \mk-select-file-from-drive-window
i = riot.mount browser, do
multiple: true
i[0].one \selected (files) ~>
files.for-each @add-file
@change-file = ~>
files = @refs.file.files
for i from 0 to files.length - 1
file = files.item i
@upload file
return false
# データ取得
data = e.data-transfer.get-data 'text'
if !data?
return false
@upload = (file) ~>
@refs.uploader.upload file
try
# パース
obj = JSON.parse data
@add-file = (file) ~>
file._remove = ~>
@files = @files.filter (x) -> x.id != file.id
@trigger \change-files @files
@update!
# (ドライブの)ファイルだったら
if obj.type == \file
@add-file obj.file
catch
# ignore
return false
@onkeydown = (e) ~>
if (e.which == 10 || e.which == 13) && (e.ctrl-key || e.meta-key)
@post!
@onpaste = (e) ~>
data = e.clipboard-data
items = data.items
for i from 0 to items.length - 1
item = items[i]
switch (item.kind)
| \file =>
@upload item.get-as-file!
@select-file = ~>
@refs.file.click!
@select-file-from-drive = ~>
browser = document.body.append-child document.create-element \mk-select-file-from-drive-window
i = riot.mount browser, do
multiple: true
i[0].one \selected (files) ~>
files.for-each @add-file
@change-file = ~>
files = @refs.file.files
for i from 0 to files.length - 1
file = files.item i
@upload file
@upload = (file) ~>
@refs.uploader.upload file
@add-file = (file) ~>
file._remove = ~>
@files = @files.filter (x) -> x.id != file.id
@files.push file
@trigger \change-files @files
@update!
@files.push file
@trigger \change-files @files
@update!
new @Sortable @refs.attaches, do
draggable: \.file
animation: 150ms
new @Sortable @refs.attaches, do
draggable: \.file
animation: 150ms
@post = (e) ~>
@wait = true
@post = (e) ~>
@wait = true
files = if @files? and @files.length > 0
then @files.map (f) -> f.id
else undefined
files = if @files? and @files.length > 0
then @files.map (f) -> f.id
else undefined
@api \posts/create do
text: @refs.text.value
media_ids: files
reply_to_id: if @in-reply-to-post? then @in-reply-to-post.id else undefined
.then (data) ~>
@trigger \post
@notify if @in-reply-to-post? then '返信しました!' else '投稿しました!'
.catch (err) ~>
console.error err
@notify '投稿できませんでした'
.then ~>
@wait = false
@update!
@api \posts/create do
text: @refs.text.value
media_ids: files
reply_to_id: if @in-reply-to-post? then @in-reply-to-post.id else undefined
.then (data) ~>
@trigger \post
@notify if @in-reply-to-post? then '返信しました!' else '投稿しました!'
.catch (err) ~>
console.error err
@notify '投稿できませんでした'
.then ~>
@wait = false
@update!
</script>
</mk-post-form>

View File

@ -1,94 +1,93 @@
mk-post-preview(title={ title })
article
a.avatar-anchor(href={ CONFIG.url + '/' + post.user.username })
img.avatar(src={ post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar', data-user-preview={ post.user_id })
div.main
header
a.name(href={ CONFIG.url + '/' + post.user.username }, data-user-preview={ post.user_id })
| { post.user.name }
span.username
| @{ post.user.username }
a.time(href={ CONFIG.url + '/' + post.user.username + '/' + post.id })
mk-time(time={ post.created_at })
div.body
mk-sub-post-content.text(post={ post })
style.
display block
margin 0
padding 0
font-size 0.9em
background #fff
> article
&:after
content ""
<mk-post-preview title="{ title }">
<article><a class="avatar-anchor" href="{ CONFIG.url + '/' + post.user.username }"><img class="avatar" src="{ post.user.avatar_url + '?thumbnail&amp;size=64' }" alt="avatar" data-user-preview="{ post.user_id }"/></a>
<div class="main">
<header><a class="name" href="{ CONFIG.url + '/' + post.user.username }" data-user-preview="{ post.user_id }">{ post.user.name }</a><span class="username">@{ post.user.username }</span><a class="time" href="{ CONFIG.url + '/' + post.user.username + '/' + post.id }">
<mk-time time="{ post.created_at }"></mk-time></a></header>
<div class="body">
<mk-sub-post-content class="text" post="{ post }"></mk-sub-post-content>
</div>
</div>
</article>
<style type="stylus">
:scope
display block
clear both
margin 0
padding 0
font-size 0.9em
background #fff
&:hover
> .main > footer > button
color #888
> article
> .avatar-anchor
display block
float left
margin 0 16px 0 0
&:after
content ""
display block
clear both
> .avatar
display block
width 52px
height 52px
margin 0
border-radius 8px
vertical-align bottom
&:hover
> .main > footer > button
color #888
> .main
float left
width calc(100% - 68px)
> .avatar-anchor
display block
float left
margin 0 16px 0 0
> header
margin-bottom 4px
white-space nowrap
> .avatar
display block
width 52px
height 52px
margin 0
border-radius 8px
vertical-align bottom
> .name
display inline
margin 0
padding 0
color #607073
font-size 1em
font-weight 700
text-align left
text-decoration none
> .main
float left
width calc(100% - 68px)
&:hover
text-decoration underline
> header
margin-bottom 4px
white-space nowrap
> .username
text-align left
margin 0 0 0 8px
color #d1d8da
> .name
display inline
margin 0
padding 0
color #607073
font-size 1em
font-weight 700
text-align left
text-decoration none
> .time
position absolute
top 0
right 0
color #b2b8bb
&:hover
text-decoration underline
> .body
> .username
text-align left
margin 0 0 0 8px
color #d1d8da
> .text
cursor default
margin 0
padding 0
font-size 1.1em
color #717171
> .time
position absolute
top 0
right 0
color #b2b8bb
script.
@mixin \date-stringify
@mixin \user-preview
> .body
@post = @opts.post
> .text
cursor default
margin 0
padding 0
font-size 1.1em
color #717171
@title = @date-stringify @post.created_at
</style>
<script>
@mixin \date-stringify
@mixin \user-preview
@post = @opts.post
@title = @date-stringify @post.created_at
</script>
</mk-post-preview>

View File

@ -1,72 +1,75 @@
mk-post-status-graph
canvas@canv(width={ opts.width }, height={ opts.height })
<mk-post-status-graph>
<canvas ref="canv" width="{ opts.width }" height="{ opts.height }"></canvas>
<style type="stylus">
:scope
display block
style.
display block
> canvas
margin 0 auto
> canvas
margin 0 auto
</style>
<script>
@mixin \api
@mixin \is-promise
script.
@mixin \api
@mixin \is-promise
@post = null
@post-promise = if @is-promise @opts.post then @opts.post else Promise.resolve @opts.post
@post = null
@post-promise = if @is-promise @opts.post then @opts.post else Promise.resolve @opts.post
@on \mount ~>
post <~ @post-promise.then
@post = post
@update!
@on \mount ~>
post <~ @post-promise.then
@post = post
@update!
@api \aggregation/posts/like do
post_id: @post.id
limit: 30days
.then (likes) ~>
likes = likes.reverse!
@api \aggregation/posts/repost do
@api \aggregation/posts/like do
post_id: @post.id
limit: 30days
.then (repost) ~>
repost = repost.reverse!
.then (likes) ~>
likes = likes.reverse!
@api \aggregation/posts/reply do
@api \aggregation/posts/repost do
post_id: @post.id
limit: 30days
.then (replies) ~>
replies = replies.reverse!
.then (repost) ~>
repost = repost.reverse!
new Chart @refs.canv, do
type: \bar
data:
labels: likes.map (x, i) ~> if i % 3 == 2 then x.date.day + '日' else ''
datasets: [
{
label: \いいね
type: \line
data: likes.map (x) ~> x.count
line-tension: 0
border-width: 2
fill: true
background-color: 'rgba(247, 121, 108, 0.2)'
point-background-color: \#fff
point-radius: 4
point-border-width: 2
border-color: \#F7796C
},
{
label: \返信
type: \bar
data: replies.map (x) ~> x.count
background-color: \#555
},
{
label: \Repost
type: \bar
data: repost.map (x) ~> x.count
background-color: \#a2d61e
}
]
options:
responsive: false
@api \aggregation/posts/reply do
post_id: @post.id
limit: 30days
.then (replies) ~>
replies = replies.reverse!
new Chart @refs.canv, do
type: \bar
data:
labels: likes.map (x, i) ~> if i % 3 == 2 then x.date.day + '日' else ''
datasets: [
{
label: \いいね
type: \line
data: likes.map (x) ~> x.count
line-tension: 0
border-width: 2
fill: true
background-color: 'rgba(247, 121, 108, 0.2)'
point-background-color: \#fff
point-radius: 4
point-border-width: 2
border-color: \#F7796C
},
{
label: \返信
type: \bar
data: replies.map (x) ~> x.count
background-color: \#555
},
{
label: \Repost
type: \bar
data: repost.map (x) ~> x.count
background-color: \#a2d61e
}
]
options:
responsive: false
</script>
</mk-post-status-graph>

View File

@ -1,92 +1,94 @@
mk-progress-dialog
mk-window@window(is-modal={ false }, can-close={ false }, width={ '500px' })
<yield to="header">
| { parent.title }
mk-ellipsis
</yield>
<yield to="content">
div.body
p.init(if={ isNaN(parent.value) })
| 待機中
mk-ellipsis
p.percentage(if={ !isNaN(parent.value) }) { Math.floor((parent.value / parent.max) * 100) }
progress(if={ !isNaN(parent.value) && parent.value < parent.max }, value={ isNaN(parent.value) ? 0 : parent.value }, max={ parent.max })
div.progress.waiting(if={ parent.value >= parent.max })
</yield>
<mk-progress-dialog>
<mk-window ref="window" is-modal="{ false }" can-close="{ false }" width="{ '500px' }">
<yield to="header">{ parent.title }
<mk-ellipsis></mk-ellipsis></yield>
<yield to="content">
<div class="body">
<p class="init" if="{ isNaN(parent.value) }">待機中
<mk-ellipsis></mk-ellipsis>
</p>
<p class="percentage" if="{ !isNaN(parent.value) }">{ Math.floor((parent.value / parent.max) * 100) }</p>
<progress if="{ !isNaN(parent.value) &amp;&amp; parent.value &lt; parent.max }" value="{ isNaN(parent.value) ? 0 : parent.value }" max="{ parent.max }"></progress>
<div class="progress waiting" if="{ parent.value &gt;= parent.max }"></div>
</div></yield>
</mk-window>
<style type="stylus">
:scope
display block
style.
display block
> mk-window
[data-yield='content']
> mk-window
[data-yield='content']
> .body
padding 18px 24px 24px 24px
> .body
padding 18px 24px 24px 24px
> .init
display block
margin 0
text-align center
color rgba(#000, 0.7)
> .init
display block
margin 0
text-align center
color rgba(#000, 0.7)
> .percentage
display block
margin 0 0 4px 0
text-align center
line-height 16px
color rgba($theme-color, 0.7)
> .percentage
display block
margin 0 0 4px 0
text-align center
line-height 16px
color rgba($theme-color, 0.7)
&:after
content '%'
&:after
content '%'
> progress
> .progress
display block
margin 0
width 100%
height 10px
background transparent
border none
border-radius 4px
overflow hidden
> progress
> .progress
display block
margin 0
width 100%
height 10px
background transparent
border none
border-radius 4px
overflow hidden
&::-webkit-progress-value
background $theme-color
&::-webkit-progress-value
background $theme-color
&::-webkit-progress-bar
background rgba($theme-color, 0.1)
&::-webkit-progress-bar
background rgba($theme-color, 0.1)
> .progress
background linear-gradient(
45deg,
lighten($theme-color, 30%) 25%,
$theme-color 25%,
$theme-color 50%,
lighten($theme-color, 30%) 50%,
lighten($theme-color, 30%) 75%,
$theme-color 75%,
$theme-color
)
background-size 32px 32px
animation progress-dialog-tag-progress-waiting 1.5s linear infinite
> .progress
background linear-gradient(
45deg,
lighten($theme-color, 30%) 25%,
$theme-color 25%,
$theme-color 50%,
lighten($theme-color, 30%) 50%,
lighten($theme-color, 30%) 75%,
$theme-color 75%,
$theme-color
)
background-size 32px 32px
animation progress-dialog-tag-progress-waiting 1.5s linear infinite
@keyframes progress-dialog-tag-progress-waiting
from {background-position: 0 0;}
to {background-position: -64px 32px;}
@keyframes progress-dialog-tag-progress-waiting
from {background-position: 0 0;}
to {background-position: -64px 32px;}
</style>
<script>
@title = @opts.title
@value = parse-int @opts.value, 10
@max = parse-int @opts.max, 10
script.
@title = @opts.title
@value = parse-int @opts.value, 10
@max = parse-int @opts.max, 10
@on \mount ~>
@refs.window.on \closed ~>
@unmount!
@on \mount ~>
@refs.window.on \closed ~>
@unmount!
@update-progress = (value, max) ~>
@value = parse-int value, 10
@max = parse-int max, 10
@update!
@update-progress = (value, max) ~>
@value = parse-int value, 10
@max = parse-int max, 10
@update!
@close = ~>
@refs.window.close!
@close = ~>
@refs.window.close!
</script>
</mk-progress-dialog>

View File

@ -1,38 +1,36 @@
mk-repost-form-window
mk-window@window(is-modal={ true }, colored={ true })
<yield to="header">
i.fa.fa-retweet
| この投稿をRepostしますか
</yield>
<yield to="content">
mk-repost-form@form(post={ parent.opts.post })
</yield>
<mk-repost-form-window>
<mk-window ref="window" is-modal="{ true }" colored="{ true }"><yield to="header"><i class="fa fa-retweet"></i>この投稿をRepostしますか</yield>
<yield to="content">
<mk-repost-form ref="form" post="{ parent.opts.post }"></mk-repost-form></yield>
</mk-window>
<style type="stylus">
:scope
> mk-window
[data-yield='header']
> i
margin-right 4px
style.
> mk-window
[data-yield='header']
> i
margin-right 4px
</style>
<script>
@on-document-keydown = (e) ~>
tag = e.target.tag-name.to-lower-case!
if tag != \input and tag != \textarea
if e.which == 27 # Esc
@refs.window.close!
script.
@on-document-keydown = (e) ~>
tag = e.target.tag-name.to-lower-case!
if tag != \input and tag != \textarea
if e.which == 27 # Esc
@on \mount ~>
@refs.window.refs.form.on \cancel ~>
@refs.window.close!
@on \mount ~>
@refs.window.refs.form.on \cancel ~>
@refs.window.close!
@refs.window.refs.form.on \posted ~>
@refs.window.close!
@refs.window.refs.form.on \posted ~>
@refs.window.close!
document.add-event-listener \keydown @on-document-keydown
document.add-event-listener \keydown @on-document-keydown
@refs.window.on \closed ~>
@unmount!
@refs.window.on \closed ~>
@unmount!
@on \unmount ~>
document.remove-event-listener \keydown @on-document-keydown
@on \unmount ~>
document.remove-event-listener \keydown @on-document-keydown
</script>
</mk-repost-form-window>

View File

@ -1,140 +1,144 @@
mk-repost-form
mk-post-preview(post={ opts.post })
div.form(if={ quote })
textarea@text(disabled={ wait }, placeholder='この投稿を引用...')
footer
a.quote(if={ !quote }, onclick={ onquote }) 引用する...
button.cancel(onclick={ cancel }) キャンセル
button.ok(onclick={ ok }) Repost
<mk-repost-form>
<mk-post-preview post="{ opts.post }"></mk-post-preview>
<div class="form" if="{ quote }">
<textarea ref="text" disabled="{ wait }" placeholder="この投稿を引用..."></textarea>
</div>
<footer><a class="quote" if="{ !quote }" onclick="{ onquote }">引用する...</a>
<button class="cancel" onclick="{ cancel }">キャンセル</button>
<button class="ok" onclick="{ ok }">Repost</button>
</footer>
<style type="stylus">
:scope
style.
> mk-post-preview
margin 16px 22px
> mk-post-preview
margin 16px 22px
> .form
[ref='text']
display block
padding 12px
margin 0
width 100%
max-width 100%
min-width 100%
min-height calc(1em + 12px + 12px)
font-size 1em
color #333
background #fff
outline none
border solid 1px rgba($theme-color, 0.1)
border-radius 4px
transition border-color .3s ease
> .form
[ref='text']
display block
padding 12px
margin 0
width 100%
max-width 100%
min-width 100%
min-height calc(1em + 12px + 12px)
font-size 1em
color #333
background #fff
outline none
border solid 1px rgba($theme-color, 0.1)
border-radius 4px
transition border-color .3s ease
&:hover
border-color rgba($theme-color, 0.2)
transition border-color .1s ease
&:hover
border-color rgba($theme-color, 0.2)
transition border-color .1s ease
&:focus
color $theme-color
border-color rgba($theme-color, 0.5)
transition border-color 0s ease
&:focus
color $theme-color
border-color rgba($theme-color, 0.5)
transition border-color 0s ease
&:disabled
opacity 0.5
&:disabled
opacity 0.5
&::-webkit-input-placeholder
color rgba($theme-color, 0.3)
&::-webkit-input-placeholder
color rgba($theme-color, 0.3)
> div
padding 16px
> div
padding 16px
> footer
height 72px
background lighten($theme-color, 95%)
> footer
height 72px
background lighten($theme-color, 95%)
> .quote
position absolute
bottom 16px
left 28px
line-height 40px
button
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
> .quote
position absolute
top -5px
right -5px
bottom -5px
left -5px
border 2px solid rgba($theme-color, 0.3)
border-radius 8px
bottom 16px
left 28px
line-height 40px
> .cancel
right 148px
color #888
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
border solid 1px #e2e2e2
button
display block
position absolute
bottom 16px
cursor pointer
padding 0
margin 0
width 120px
height 40px
font-size 1em
outline none
border-radius 4px
&:hover
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
border-color #dcdcdc
&: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
&:active
background #ececec
border-color #dcdcdc
> .cancel
right 148px
color #888
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
border solid 1px #e2e2e2
> .ok
right 16px
font-weight bold
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%)
&:hover
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
border-color #dcdcdc
&:hover
background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%)
border-color $theme-color
&:active
background #ececec
border-color #dcdcdc
&:active
background $theme-color
border-color $theme-color
> .ok
right 16px
font-weight bold
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%)
script.
@mixin \api
@mixin \notify
&:hover
background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%)
border-color $theme-color
@wait = false
@quote = false
&:active
background $theme-color
border-color $theme-color
@cancel = ~>
@trigger \cancel
</style>
<script>
@mixin \api
@mixin \notify
@ok = ~>
@wait = true
@api \posts/create do
repost_id: @opts.post.id
text: if @quote then @refs.text.value else undefined
.then (data) ~>
@trigger \posted
@notify 'Repostしました'
.catch (err) ~>
console.error err
@notify 'Repostできませんでした'
.then ~>
@wait = false
@update!
@wait = false
@quote = false
@onquote = ~>
@quote = true
@cancel = ~>
@trigger \cancel
@ok = ~>
@wait = true
@api \posts/create do
repost_id: @opts.post.id
text: if @quote then @refs.text.value else undefined
.then (data) ~>
@trigger \posted
@notify 'Repostしました'
.catch (err) ~>
console.error err
@notify 'Repostできませんでした'
.then ~>
@wait = false
@update!
@onquote = ~>
@quote = true
</script>
</mk-repost-form>

View File

@ -1,88 +1,86 @@
mk-search-posts
div.loading(if={ is-loading })
mk-ellipsis-icon
p.empty(if={ is-empty })
i.fa.fa-search
| 「{ query }」に関する投稿は見つかりませんでした。
mk-timeline@timeline
<yield to="footer">
i.fa.fa-moon-o(if={ !parent.more-loading })
i.fa.fa-spinner.fa-pulse.fa-fw(if={ parent.more-loading })
</yield>
style.
display block
background #fff
> .loading
padding 64px 0
> .empty
display block
margin 0 auto
padding 32px
max-width 400px
text-align center
color #999
> i
<mk-search-posts>
<div class="loading" if="{ isLoading }">
<mk-ellipsis-icon></mk-ellipsis-icon>
</div>
<p class="empty" if="{ isEmpty }"><i class="fa fa-search"></i>「{ query }」に関する投稿は見つかりませんでした。</p>
<mk-timeline ref="timeline"><yield to="footer"><i class="fa fa-moon-o" if="{ !parent.moreLoading }"></i><i class="fa fa-spinner fa-pulse fa-fw" if="{ parent.moreLoading }"></i></yield></mk-timeline>
<style type="stylus">
:scope
display block
margin-bottom 16px
font-size 3em
color #ccc
background #fff
script.
@mixin \api
@mixin \get-post-summary
> .loading
padding 64px 0
@query = @opts.query
@is-loading = true
@is-empty = false
@more-loading = false
@page = 0
> .empty
display block
margin 0 auto
padding 32px
max-width 400px
text-align center
color #999
@on \mount ~>
document.add-event-listener \keydown @on-document-keydown
window.add-event-listener \scroll @on-scroll
> i
display block
margin-bottom 16px
font-size 3em
color #ccc
@api \posts/search do
query: @query
.then (posts) ~>
@is-loading = false
@is-empty = posts.length == 0
</style>
<script>
@mixin \api
@mixin \get-post-summary
@query = @opts.query
@is-loading = true
@is-empty = false
@more-loading = false
@page = 0
@on \mount ~>
document.add-event-listener \keydown @on-document-keydown
window.add-event-listener \scroll @on-scroll
@api \posts/search do
query: @query
.then (posts) ~>
@is-loading = false
@is-empty = posts.length == 0
@update!
@refs.timeline.set-posts posts
@trigger \loaded
.catch (err) ~>
console.error err
@on \unmount ~>
document.remove-event-listener \keydown @on-document-keydown
window.remove-event-listener \scroll @on-scroll
@on-document-keydown = (e) ~>
tag = e.target.tag-name.to-lower-case!
if tag != \input and tag != \textarea
if e.which == 84 # t
@refs.timeline.focus!
@more = ~>
if @more-loading or @is-loading or @timeline.posts.length == 0
return
@more-loading = true
@update!
@refs.timeline.set-posts posts
@trigger \loaded
.catch (err) ~>
console.error err
@api \posts/search do
query: @query
page: @page + 1
.then (posts) ~>
@more-loading = false
@page++
@update!
@refs.timeline.prepend-posts posts
.catch (err) ~>
console.error err
@on \unmount ~>
document.remove-event-listener \keydown @on-document-keydown
window.remove-event-listener \scroll @on-scroll
@on-document-keydown = (e) ~>
tag = e.target.tag-name.to-lower-case!
if tag != \input and tag != \textarea
if e.which == 84 # t
@refs.timeline.focus!
@more = ~>
if @more-loading or @is-loading or @timeline.posts.length == 0
return
@more-loading = true
@update!
@api \posts/search do
query: @query
page: @page + 1
.then (posts) ~>
@more-loading = false
@page++
@update!
@refs.timeline.prepend-posts posts
.catch (err) ~>
console.error err
@on-scroll = ~>
current = window.scroll-y + window.inner-height
if current > document.body.offset-height - 16 # 遊び
@more!
@on-scroll = ~>
current = window.scroll-y + window.inner-height
if current > document.body.offset-height - 16 # 遊び
@more!
</script>
</mk-search-posts>

View File

@ -1,28 +1,32 @@
mk-search
header
h1 { query }
mk-search-posts@posts(query={ query })
<mk-search>
<header>
<h1>{ query }</h1>
</header>
<mk-search-posts ref="posts" query="{ query }"></mk-search-posts>
<style type="stylus">
:scope
display block
padding-bottom 32px
style.
display block
padding-bottom 32px
> header
width 100%
max-width 600px
margin 0 auto
color #555
> header
width 100%
max-width 600px
margin 0 auto
color #555
> mk-search-posts
max-width 600px
margin 0 auto
border solid 1px rgba(0, 0, 0, 0.075)
border-radius 6px
overflow hidden
> mk-search-posts
max-width 600px
margin 0 auto
border solid 1px rgba(0, 0, 0, 0.075)
border-radius 6px
overflow hidden
</style>
<script>
@query = @opts.query
script.
@query = @opts.query
@on \mount ~>
@refs.posts.on \loaded ~>
@trigger \loaded
@on \mount ~>
@refs.posts.on \loaded ~>
@trigger \loaded
</script>
</mk-search>

View File

@ -1,160 +1,161 @@
mk-select-file-from-drive-window
mk-window@window(is-modal={ true }, width={ '800px' }, height={ '500px' })
<yield to="header">
mk-raw(content={ parent.title })
span.count(if={ parent.multiple && parent.file.length > 0 }) ({ parent.file.length }ファイル選択中)
</yield>
<yield to="content">
mk-drive-browser@browser(multiple={ parent.multiple })
div
button.upload(title='PCからドライブにファイルをアップロード', onclick={ parent.upload }): i.fa.fa-upload
button.cancel(onclick={ parent.close }) キャンセル
button.ok(disabled={ parent.multiple && parent.file.length == 0 }, onclick={ parent.ok }) 決定
</yield>
<mk-select-file-from-drive-window>
<mk-window ref="window" is-modal="{ true }" width="{ '800px' }" height="{ '500px' }"><yield to="header">
<mk-raw content="{ parent.title }"></mk-raw><span class="count" if="{ parent.multiple &amp;&amp; parent.file.length &gt; 0 }">({ parent.file.length }ファイル選択中)</span></yield>
<yield to="content">
<mk-drive-browser ref="browser" multiple="{ parent.multiple }"></mk-drive-browser>
<div>
<button class="upload" title="PCからドライブにファイルをアップロード" onclick="{ parent.upload }"><i class="fa fa-upload"></i></button>
<button class="cancel" onclick="{ parent.close }">キャンセル</button>
<button class="ok" disabled="{ parent.multiple &amp;&amp; parent.file.length == 0 }" onclick="{ parent.ok }">決定</button>
</div></yield>
</mk-window>
<style type="stylus">
:scope
> mk-window
[data-yield='header']
> mk-raw
> i
margin-right 4px
style.
> mk-window
[data-yield='header']
> mk-raw
> i
margin-right 4px
.count
margin-left 8px
opacity 0.7
[data-yield='content']
> mk-drive-browser
height calc(100% - 72px)
> div
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
.count
margin-left 8px
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%)
[data-yield='content']
> mk-drive-browser
height calc(100% - 72px)
&:not(:disabled)
font-weight bold
> div
height 72px
background lighten($theme-color, 95%)
&:hover:not(:disabled)
background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%)
border-color $theme-color
.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
&:active:not(:disabled)
background $theme-color
border-color $theme-color
&:hover
background transparent
border-color rgba($theme-color, 0.3)
.cancel
right 148px
color #888
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
border solid 1px #e2e2e2
&: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
&:hover
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
border-color #dcdcdc
&: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
&:active
background #ececec
border-color #dcdcdc
.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
script.
@file = []
&: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
@multiple = if @opts.multiple? then @opts.multiple else false
@title = @opts.title || '<i class="fa fa-file-o"></i>ファイルを選択'
&:disabled
opacity 0.7
cursor default
@on \mount ~>
@refs.window.refs.browser.on \selected (file) ~>
@file = file
@ok!
.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%)
@refs.window.refs.browser.on \change-selection (files) ~>
@file = files
@update!
&:not(:disabled)
font-weight bold
@refs.window.on \closed ~>
@unmount!
&:hover:not(:disabled)
background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%)
border-color $theme-color
@close = ~>
@refs.window.close!
&:active:not(:disabled)
background $theme-color
border-color $theme-color
@upload = ~>
@refs.window.refs.browser.select-local-file!
.cancel
right 148px
color #888
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
border solid 1px #e2e2e2
@ok = ~>
@trigger \selected @file
@refs.window.close!
&:hover
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
border-color #dcdcdc
&:active
background #ececec
border-color #dcdcdc
</style>
<script>
@file = []
@multiple = if @opts.multiple? then @opts.multiple else false
@title = @opts.title || '<i class="fa fa-file-o"></i>ファイルを選択'
@on \mount ~>
@refs.window.refs.browser.on \selected (file) ~>
@file = file
@ok!
@refs.window.refs.browser.on \change-selection (files) ~>
@file = files
@update!
@refs.window.on \closed ~>
@unmount!
@close = ~>
@refs.window.close!
@upload = ~>
@refs.window.refs.browser.select-local-file!
@ok = ~>
@trigger \selected @file
@refs.window.close!
</script>
</mk-select-file-from-drive-window>

View File

@ -1,44 +1,46 @@
mk-set-avatar-suggestion(onclick={ set })
p
b アバターを設定
| してみませんか?
button(onclick={ close }): i.fa.fa-times
style.
display block
cursor pointer
color #fff
background #a8cad0
&:hover
background #70abb5
> p
display block
margin 0 auto
padding 8px
max-width 1024px
> a
font-weight bold
<mk-set-avatar-suggestion onclick="{ set }">
<p><b>アバターを設定</b>してみませんか?
<button onclick="{ close }"><i class="fa fa-times"></i></button>
</p>
<style type="stylus">
:scope
display block
cursor pointer
color #fff
background #a8cad0
> button
position absolute
top 0
right 0
padding 8px
color #fff
&:hover
background #70abb5
script.
@mixin \i
@mixin \update-avatar
> p
display block
margin 0 auto
padding 8px
max-width 1024px
@set = ~>
@update-avatar @I, (i) ~>
@update-i i
> a
font-weight bold
color #fff
@close = (e) ~>
e.prevent-default!
e.stop-propagation!
@unmount!
> button
position absolute
top 0
right 0
padding 8px
color #fff
</style>
<script>
@mixin \i
@mixin \update-avatar
@set = ~>
@update-avatar @I, (i) ~>
@update-i i
@close = (e) ~>
e.prevent-default!
e.stop-propagation!
@unmount!
</script>
</mk-set-avatar-suggestion>

View File

@ -1,44 +1,46 @@
mk-set-banner-suggestion(onclick={ set })
p
b バナーを設定
| してみませんか?
button(onclick={ close }): i.fa.fa-times
style.
display block
cursor pointer
color #fff
background #a8cad0
&:hover
background #70abb5
> p
display block
margin 0 auto
padding 8px
max-width 1024px
> a
font-weight bold
<mk-set-banner-suggestion onclick="{ set }">
<p><b>バナーを設定</b>してみませんか?
<button onclick="{ close }"><i class="fa fa-times"></i></button>
</p>
<style type="stylus">
:scope
display block
cursor pointer
color #fff
background #a8cad0
> button
position absolute
top 0
right 0
padding 8px
color #fff
&:hover
background #70abb5
script.
@mixin \i
@mixin \update-banner
> p
display block
margin 0 auto
padding 8px
max-width 1024px
@set = ~>
@update-banner @I, (i) ~>
@update-i i
> a
font-weight bold
color #fff
@close = (e) ~>
e.prevent-default!
e.stop-propagation!
@unmount!
> button
position absolute
top 0
right 0
padding 8px
color #fff
</style>
<script>
@mixin \i
@mixin \update-banner
@set = ~>
@update-banner @I, (i) ~>
@update-i i
@close = (e) ~>
e.prevent-default!
e.stop-propagation!
@unmount!
</script>
</mk-set-banner-suggestion>

View File

@ -1,26 +1,25 @@
mk-settings-window
mk-window@window(is-modal={ true }, width={ '700px' }, height={ '550px' })
<yield to="header">
i.fa.fa-cog
| 設定
</yield>
<yield to="content">
mk-settings
</yield>
<mk-settings-window>
<mk-window ref="window" is-modal="{ true }" width="{ '700px' }" height="{ '550px' }"><yield to="header"><i class="fa fa-cog"></i>設定</yield>
<yield to="content">
<mk-settings></mk-settings></yield>
</mk-window>
<style type="stylus">
:scope
> mk-window
[data-yield='header']
> i
margin-right 4px
style.
> mk-window
[data-yield='header']
> i
margin-right 4px
[data-yield='content']
overflow auto
[data-yield='content']
overflow auto
</style>
<script>
@on \mount ~>
@refs.window.on \closed ~>
@unmount!
script.
@on \mount ~>
@refs.window.on \closed ~>
@unmount!
@close = ~>
@refs.window.close!
@close = ~>
@refs.window.close!
</script>
</mk-settings-window>

View File

@ -1,271 +1,266 @@
mk-settings
div.nav
p(class={ active: page == 'account' }, onmousedown={ set-page.bind(null, 'account') })
i.fa.fa-fw.fa-user
| アカウント
p(class={ active: page == 'web' }, onmousedown={ set-page.bind(null, 'web') })
i.fa.fa-fw.fa-desktop
| Web
p(class={ active: page == 'notification' }, onmousedown={ set-page.bind(null, 'notification') })
i.fa.fa-fw.fa-bell-o
| 通知
p(class={ active: page == 'drive' }, onmousedown={ set-page.bind(null, 'drive') })
i.fa.fa-fw.fa-cloud
| ドライブ
p(class={ active: page == 'apps' }, onmousedown={ set-page.bind(null, 'apps') })
i.fa.fa-fw.fa-puzzle-piece
| アプリ
p(class={ active: page == 'signin' }, onmousedown={ set-page.bind(null, 'signin') })
i.fa.fa-fw.fa-sign-in
| ログイン履歴
p(class={ active: page == 'password' }, onmousedown={ set-page.bind(null, 'password') })
i.fa.fa-fw.fa-unlock-alt
| パスワード
p(class={ active: page == 'api' }, onmousedown={ set-page.bind(null, 'api') })
i.fa.fa-fw.fa-key
| API
div.pages
section.account(show={ page == 'account' })
h1 アカウント
label.avatar
p アバター
img.avatar(src={ I.avatar_url + '?thumbnail&size=64' }, alt='avatar')
button.style-normal(onclick={ avatar }) 画像を選択
label
p 名前
input@account-name(type='text', value={ I.name })
label
p 場所
input@account-location(type='text', value={ I.location })
label
p 自己紹介
textarea@account-bio { I.bio }
label
p 誕生日
input@account-birthday(type='date', value={ I.birthday })
button.style-primary(onclick={ update-account }) 保存
section.web(show={ page == 'web' })
h1 デザイン
label
p 壁紙
button.style-normal(onclick={ wallpaper }) 画像を選択
section.web(show={ page == 'web' })
h1 その他
label.checkbox
input(type='checkbox', checked={ I.data.cache }, onclick={ update-cache })
p 読み込みを高速化する
p API通信時に新鮮なユーザー情報をキャッシュすることでフェッチのオーバーヘッドを無くします。(実験的)
label.checkbox
input(type='checkbox', checked={ I.data.debug }, onclick={ update-debug })
p 開発者モード
p デバッグ等の開発者モードを有効にします。
label.checkbox
input(type='checkbox', checked={ I.data.nya }, onclick={ update-nya })
p <i>な</i>を<i>にゃ</i>に変換する
p 攻撃的な投稿が多少和らぐ可能性があります。
section.signin(show={ page == 'signin' })
h1 ログイン履歴
mk-signin-history
section.api(show={ page == 'api' })
h1 API
p
| Token:
code { I.token }
p APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。
p アカウントを乗っ取られてしまう可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。
p
| 万が一このトークンが漏れたりその可能性がある場合は
button.regenerate(onclick={ regenerate-token }) トークンを再生成
| できます。(副作用として、ログインしているすべてのデバイスでログアウトが発生します)
style.
display block
input:not([type])
input[type='text']
input[type='password']
input[type='email']
textarea
padding 8px
width 100%
font-size 16px
color #55595c
border solid 1px #dadada
border-radius 4px
&:hover
border-color #aeaeae
&:focus
border-color #aeaeae
> .nav
position absolute
top 0
left 0
width 200px
height 100%
padding 16px 0 0 0
border-right solid 1px #ddd
> p
<mk-settings>
<div class="nav">
<p class="{ active: page == 'account' }" onmousedown="{ setPage.bind(null, 'account') }"><i class="fa fa-fw fa-user"></i>アカウント</p>
<p class="{ active: page == 'web' }" onmousedown="{ setPage.bind(null, 'web') }"><i class="fa fa-fw fa-desktop"></i>Web</p>
<p class="{ active: page == 'notification' }" onmousedown="{ setPage.bind(null, 'notification') }"><i class="fa fa-fw fa-bell-o"></i>通知</p>
<p class="{ active: page == 'drive' }" onmousedown="{ setPage.bind(null, 'drive') }"><i class="fa fa-fw fa-cloud"></i>ドライブ</p>
<p class="{ active: page == 'apps' }" onmousedown="{ setPage.bind(null, 'apps') }"><i class="fa fa-fw fa-puzzle-piece"></i>アプリ</p>
<p class="{ active: page == 'signin' }" onmousedown="{ setPage.bind(null, 'signin') }"><i class="fa fa-fw fa-sign-in"></i>ログイン履歴</p>
<p class="{ active: page == 'password' }" onmousedown="{ setPage.bind(null, 'password') }"><i class="fa fa-fw fa-unlock-alt"></i>パスワード</p>
<p class="{ active: page == 'api' }" onmousedown="{ setPage.bind(null, 'api') }"><i class="fa fa-fw fa-key"></i>API</p>
</div>
<div class="pages">
<section class="account" show="{ page == 'account' }">
<h1>アカウント</h1>
<label class="avatar">
<p>アバター</p><img class="avatar" src="{ I.avatar_url + '?thumbnail&amp;size=64' }" alt="avatar"/>
<button class="style-normal" onclick="{ avatar }">画像を選択</button>
</label>
<label>
<p>名前</p>
<input ref="accountName" type="text" value="{ I.name }"/>
</label>
<label>
<p>場所</p>
<input ref="accountLocation" type="text" value="{ I.location }"/>
</label>
<label>
<p>自己紹介</p>
<textarea ref="accountBio">{ I.bio }</textarea>
</label>
<label>
<p>誕生日</p>
<input ref="accountBirthday" type="date" value="{ I.birthday }"/>
</label>
<button class="style-primary" onclick="{ updateAccount }">保存</button>
</section>
<section class="web" show="{ page == 'web' }">
<h1>デザイン</h1>
<label>
<p>壁紙</p>
<button class="style-normal" onclick="{ wallpaper }">画像を選択</button>
</label>
</section>
<section class="web" show="{ page == 'web' }">
<h1>その他</h1>
<label class="checkbox">
<input type="checkbox" checked="{ I.data.cache }" onclick="{ updateCache }"/>
<p>読み込みを高速化する</p>
<p>API通信時に新鮮なユーザー情報をキャッシュすることでフェッチのオーバーヘッドを無くします。(実験的)</p>
</label>
<label class="checkbox">
<input type="checkbox" checked="{ I.data.debug }" onclick="{ updateDebug }"/>
<p>開発者モード</p>
<p>デバッグ等の開発者モードを有効にします。</p>
</label>
<label class="checkbox">
<input type="checkbox" checked="{ I.data.nya }" onclick="{ updateNya }"/>
<p><i>な</i>を<i>にゃ</i>に変換する</p>
<p>攻撃的な投稿が多少和らぐ可能性があります。</p>
</label>
</section>
<section class="signin" show="{ page == 'signin' }">
<h1>ログイン履歴</h1>
<mk-signin-history></mk-signin-history>
</section>
<section class="api" show="{ page == 'api' }">
<h1>API</h1>
<p>Token:<code>{ I.token }</code></p>
<p>APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。</p>
<p>アカウントを乗っ取られてしまう可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。</p>
<p>万が一このトークンが漏れたりその可能性がある場合は
<button class="regenerate" onclick="{ regenerateToken }">トークンを再生成</button>できます。(副作用として、ログインしているすべてのデバイスでログアウトが発生します)
</p>
</section>
</div>
<style type="stylus">
:scope
display block
padding 10px 16px
margin 0
color #666
cursor pointer
-ms-user-select none
-moz-user-select none
-webkit-user-select none
user-select none
input:not([type])
input[type='text']
input[type='password']
input[type='email']
textarea
padding 8px
width 100%
font-size 16px
color #55595c
border solid 1px #dadada
border-radius 4px
transition margin-left 0.2s ease
&:hover
border-color #aeaeae
> i
margin-right 4px
&:focus
border-color #aeaeae
&:hover
color #555
&.active
margin-left 8px
color $theme-color !important
> .pages
position absolute
top 0
left 200px
width calc(100% - 200px)
> section
padding 32px
// & + section
// margin-top 16px
h1
display block
margin 0
padding 0 0 8px 0
font-size 1em
color #555
border-bottom solid 1px #eee
label
display block
margin 16px 0
&:after
content ""
display block
clear both
> .nav
position absolute
top 0
left 0
width 200px
height 100%
padding 16px 0 0 0
border-right solid 1px #ddd
> p
margin 0 0 8px 0
font-weight bold
color #373a3c
display block
padding 10px 16px
margin 0
color #666
cursor pointer
&.checkbox
> input
position absolute
top 0
left 0
-ms-user-select none
-moz-user-select none
-webkit-user-select none
user-select none
&:checked + p
color $theme-color
transition margin-left 0.2s ease
> p
width calc(100% - 32px)
margin 0 0 0 32px
font-weight bold
&:last-child
font-weight normal
color #999
&.account
> .general
> .avatar
> img
display block
float left
width 64px
height 64px
border-radius 4px
> button
float left
margin-left 8px
&.api
code
padding 4px
background #eee
.regenerate
display inline
color $theme-color
> i
margin-right 4px
&:hover
text-decoration underline
color #555
script.
@mixin \i
@mixin \api
@mixin \dialog
@mixin \update-avatar
@mixin \update-wallpaper
&.active
margin-left 8px
color $theme-color !important
@page = \account
> .pages
position absolute
top 0
left 200px
width calc(100% - 200px)
@set-page = (page) ~>
@page = page
> section
padding 32px
@avatar = ~>
@update-avatar @I, (i) ~>
@update-i i
// & + section
// margin-top 16px
@wallpaper = ~>
@update-wallpaper @I, (i) ~>
@update-i i
h1
display block
margin 0
padding 0 0 8px 0
font-size 1em
color #555
border-bottom solid 1px #eee
@update-account = ~>
@api \i/update do
name: @refs.account-name.value
location: @refs.account-location.value
bio: @refs.account-bio.value
birthday: @refs.account-birthday.value
.then (i) ~>
@update-i i
alert \ok
.catch (err) ~>
console.error err
label
display block
margin 16px 0
@update-cache = ~>
@I.data.cache = !@I.data.cache
@api \i/appdata/set do
data: JSON.stringify do
cache: @I.data.cache
.then ~>
@update-i!
&:after
content ""
display block
clear both
@update-debug = ~>
@I.data.debug = !@I.data.debug
@api \i/appdata/set do
data: JSON.stringify do
debug: @I.data.debug
.then ~>
@update-i!
> p
margin 0 0 8px 0
font-weight bold
color #373a3c
@update-nya = ~>
@I.data.nya = !@I.data.nya
@api \i/appdata/set do
data: JSON.stringify do
nya: @I.data.nya
.then ~>
@update-i!
&.checkbox
> input
position absolute
top 0
left 0
&:checked + p
color $theme-color
> p
width calc(100% - 32px)
margin 0 0 0 32px
font-weight bold
&:last-child
font-weight normal
color #999
&.account
> .general
> .avatar
> img
display block
float left
width 64px
height 64px
border-radius 4px
> button
float left
margin-left 8px
&.api
code
padding 4px
background #eee
.regenerate
display inline
color $theme-color
&:hover
text-decoration underline
</style>
<script>
@mixin \i
@mixin \api
@mixin \dialog
@mixin \update-avatar
@mixin \update-wallpaper
@page = \account
@set-page = (page) ~>
@page = page
@avatar = ~>
@update-avatar @I, (i) ~>
@update-i i
@wallpaper = ~>
@update-wallpaper @I, (i) ~>
@update-i i
@update-account = ~>
@api \i/update do
name: @refs.account-name.value
location: @refs.account-location.value
bio: @refs.account-bio.value
birthday: @refs.account-birthday.value
.then (i) ~>
@update-i i
alert \ok
.catch (err) ~>
console.error err
@update-cache = ~>
@I.data.cache = !@I.data.cache
@api \i/appdata/set do
data: JSON.stringify do
cache: @I.data.cache
.then ~>
@update-i!
@update-debug = ~>
@I.data.debug = !@I.data.debug
@api \i/appdata/set do
data: JSON.stringify do
debug: @I.data.debug
.then ~>
@update-i!
@update-nya = ~>
@I.data.nya = !@I.data.nya
@api \i/appdata/set do
data: JSON.stringify do
nya: @I.data.nya
.then ~>
@update-i!
</script>
</mk-settings>

View File

@ -1,73 +1,75 @@
mk-signin-history
div.records(if={ history.length != 0 })
div(each={ history })
mk-time(time={ created_at })
header
i.fa.fa-check(if={ success })
i.fa.fa-times(if={ !success })
span.ip { ip }
pre: code { JSON.stringify(headers, null, ' ') }
<mk-signin-history>
<div class="records" if="{ history.length != 0 }">
<div each="{ history }">
<mk-time time="{ created_at }"></mk-time>
<header><i class="fa fa-check" if="{ success }"></i><i class="fa fa-times" if="{ !success }"></i><span class="ip">{ ip }</span></header>
<pre><code>{ JSON.stringify(headers, null, ' ') }</code></pre>
</div>
</div>
<style type="stylus">
:scope
display block
style.
display block
> .records
> div
padding 16px 0 0 0
border-bottom solid 1px #eee
> .records
> div
padding 16px 0 0 0
border-bottom solid 1px #eee
> header
> header
> i
margin-right 8px
> i
margin-right 8px
&.fa-check
color #0fda82
&.fa-check
color #0fda82
&.fa-times
color #ff3100
&.fa-times
color #ff3100
> .ip
display inline-block
color #444
background #f8f8f8
> .ip
display inline-block
color #444
background #f8f8f8
> mk-time
position absolute
top 16px
right 0
color #777
> mk-time
position absolute
top 16px
right 0
color #777
> pre
overflow auto
max-height 100px
> pre
overflow auto
max-height 100px
> code
white-space pre-wrap
word-break break-all
color #4a535a
> code
white-space pre-wrap
word-break break-all
color #4a535a
</style>
<script>
@mixin \api
@mixin \stream
script.
@mixin \api
@mixin \stream
@history = []
@fetching = true
@history = []
@fetching = true
@on \mount ~>
@api \i/signin_history
.then (history) ~>
@history = history
@fetching = false
@update!
.catch (err) ~>
console.error err
@on \mount ~>
@api \i/signin_history
.then (history) ~>
@history = history
@fetching = false
@stream.on \signin @on-signin
@on \unmount ~>
@stream.off \signin @on-signin
@on-signin = (signin) ~>
@history.unshift signin
@update!
.catch (err) ~>
console.error err
@stream.on \signin @on-signin
@on \unmount ~>
@stream.off \signin @on-signin
@on-signin = (signin) ~>
@history.unshift signin
@update!
</script>
</mk-signin-history>

View File

@ -1,59 +1,54 @@
mk-stream-indicator
p(if={ state == 'initializing' })
i.fa.fa-spinner.fa-spin
span
| 接続中
mk-ellipsis
p(if={ state == 'reconnecting' })
i.fa.fa-spinner.fa-spin
span
| 切断されました 接続中
mk-ellipsis
p(if={ state == 'connected' })
i.fa.fa-check
span 接続完了
<mk-stream-indicator>
<p if="{ state == 'initializing' }"><i class="fa fa-spinner fa-spin"></i><span>接続中
<mk-ellipsis></mk-ellipsis></span></p>
<p if="{ state == 'reconnecting' }"><i class="fa fa-spinner fa-spin"></i><span>切断されました 接続中
<mk-ellipsis></mk-ellipsis></span></p>
<p if="{ state == 'connected' }"><i class="fa fa-check"></i><span>接続完了</span></p>
<style type="stylus">
:scope
display block
pointer-events none
position fixed
z-index 16384
bottom 8px
right 8px
margin 0
padding 6px 12px
font-size 0.9em
color #fff
background rgba(0, 0, 0, 0.8)
style.
display block
pointer-events none
position fixed
z-index 16384
bottom 8px
right 8px
margin 0
padding 6px 12px
font-size 0.9em
color #fff
background rgba(0, 0, 0, 0.8)
> p
display block
margin 0
> p
display block
margin 0
> i
margin-right 0.25em
> i
margin-right 0.25em
</style>
<script>
@mixin \stream
script.
@mixin \stream
@on \before-mount ~>
@state = @get-stream-state!
@on \before-mount ~>
@state = @get-stream-state!
if @state == \connected
@root.style.opacity = 0
if @state == \connected
@root.style.opacity = 0
@stream-state-ev.on \connected ~>
@state = @get-stream-state!
@update!
set-timeout ~>
Velocity @root, {
opacity: 0
} 200ms \linear
, 1000ms
@stream-state-ev.on \connected ~>
@state = @get-stream-state!
@update!
set-timeout ~>
@stream-state-ev.on \closed ~>
@state = @get-stream-state!
@update!
Velocity @root, {
opacity: 0
} 200ms \linear
, 1000ms
@stream-state-ev.on \closed ~>
@state = @get-stream-state!
@update!
Velocity @root, {
opacity: 1
} 0ms
opacity: 1
} 0ms
</script>
</mk-stream-indicator>

View File

@ -1,37 +1,38 @@
mk-sub-post-content
div.body
a.reply(if={ post.reply_to_id }): i.fa.fa-reply
span@text
a.quote(if={ post.repost_id }, href={ '/post:' + post.repost_id }) RP: ...
details(if={ post.media })
summary ({ post.media.length }枚の画像)
mk-images-viewer(images={ post.media })
<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>
<details if="{ post.media }">
<summary>({ post.media.length }枚の画像)</summary>
<mk-images-viewer images="{ post.media }"></mk-images-viewer>
</details>
<style type="stylus">
:scope
display block
word-wrap break-word
style.
display block
word-wrap break-word
> .body
> .reply
margin-right 6px
color #717171
> .body
> .reply
margin-right 6px
color #717171
> .quote
margin-left 4px
font-style oblique
color #a0bf46
> .quote
margin-left 4px
font-style oblique
color #a0bf46
</style>
<script>
@mixin \text
@mixin \user-preview
script.
@mixin \text
@mixin \user-preview
@post = @opts.post
@post = @opts.post
@on \mount ~>
if @post.text?
tokens = @analyze @post.text
@refs.text.innerHTML = @compile tokens, false
@on \mount ~>
if @post.text?
tokens = @analyze @post.text
@refs.text.innerHTML = @compile tokens, false
@refs.text.children.for-each (e) ~>
if e.tag-name == \MK-URL
riot.mount e
@refs.text.children.for-each (e) ~>
if e.tag-name == \MK-URL
riot.mount e
</script>
</mk-sub-post-content>

View File

@ -1,95 +1,99 @@
mk-timeline-post-sub(title={ title })
article
a.avatar-anchor(href={ CONFIG.url + '/' + post.user.username })
img.avatar(src={ post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar', data-user-preview={ post.user_id })
div.main
header
a.name(href={ CONFIG.url + '/' + post.user.username }, data-user-preview={ post.user_id })
| { post.user.name }
span.username
| @{ post.user.username }
a.created-at(href={ CONFIG.url + '/' + post.user.username + '/' + post.id })
mk-time(time={ post.created_at })
div.body
mk-sub-post-content.text(post={ post })
<mk-timeline-post-sub title="{ title }">
<article><a class="avatar-anchor" href="{ CONFIG.url + '/' + post.user.username }"><img class="avatar" src="{ post.user.avatar_url + '?thumbnail&amp;size=64' }" alt="avatar" data-user-preview="{ post.user_id }"/></a>
<div class="main">
<header><a class="name" href="{ CONFIG.url + '/' + post.user.username }" data-user-preview="{ post.user_id }">{ post.user.name }</a><span class="username">@{ post.user.username }</span><a class="created-at" href="{ CONFIG.url + '/' + post.user.username + '/' + post.id }">
<mk-time time="{ post.created_at }"></mk-time></a></header>
<div class="body">
<mk-sub-post-content class="text" post="{ post }"></mk-sub-post-content>
</div>
</div>
</article>
<script>
@mixin \date-stringify
@mixin \user-preview
script.
@mixin \date-stringify
@mixin \user-preview
@post = @opts.post
@post = @opts.post
@title = @date-stringify @post.created_at
@title = @date-stringify @post.created_at
style.
display block
margin 0
padding 0
font-size 0.9em
> article
padding 16px
&:after
content ""
</script>
<style type="stylus">
:scope
display block
clear both
margin 0
padding 0
font-size 0.9em
&:hover
> .main > footer > button
color #888
> article
padding 16px
> .avatar-anchor
display block
float left
margin 0 14px 0 0
&:after
content ""
display block
clear both
> .avatar
display block
width 52px
height 52px
margin 0
border-radius 8px
vertical-align bottom
&:hover
> .main > footer > button
color #888
> .main
float left
width calc(100% - 66px)
> .avatar-anchor
display block
float left
margin 0 14px 0 0
> header
margin-bottom 4px
white-space nowrap
line-height 21px
> .avatar
display block
width 52px
height 52px
margin 0
border-radius 8px
vertical-align bottom
> .name
display inline
margin 0
padding 0
color #607073
font-size 1em
font-weight 700
text-align left
text-decoration none
> .main
float left
width calc(100% - 66px)
&:hover
text-decoration underline
> header
margin-bottom 4px
white-space nowrap
line-height 21px
> .username
text-align left
margin 0 0 0 8px
color #d1d8da
> .name
display inline
margin 0
padding 0
color #607073
font-size 1em
font-weight 700
text-align left
text-decoration none
> .created-at
position absolute
top 0
right 0
color #b2b8bb
&:hover
text-decoration underline
> .body
> .username
text-align left
margin 0 0 0 8px
color #d1d8da
> .text
cursor default
margin 0
padding 0
font-size 1.1em
color #717171
> .created-at
position absolute
top 0
right 0
color #b2b8bb
> .body
> .text
cursor default
margin 0
padding 0
font-size 1.1em
color #717171
</style>
</mk-timeline-post-sub>

View File

@ -1,376 +1,332 @@
mk-timeline-post(tabindex='-1', title={ title }, onkeydown={ on-key-down })
div.reply-to(if={ p.reply_to })
mk-timeline-post-sub(post={ p.reply_to })
div.repost(if={ is-repost })
p
a.avatar-anchor(href={ CONFIG.url + '/' + post.user.username }, data-user-preview={ post.user_id }): img.avatar(src={ post.user.avatar_url + '?thumbnail&size=32' }, alt='avatar')
i.fa.fa-retweet
a.name(href={ CONFIG.url + '/' + post.user.username }, data-user-preview={ post.user_id }) { post.user.name }
| がRepost
mk-time(time={ post.created_at })
article
a.avatar-anchor(href={ CONFIG.url + '/' + p.user.username })
img.avatar(src={ p.user.avatar_url + '?thumbnail&size=64' }, alt='avatar', data-user-preview={ p.user.id })
div.main
header
a.name(href={ CONFIG.url + '/' + p.user.username }, data-user-preview={ p.user.id })
| { p.user.name }
span.username
| @{ p.user.username }
a.created-at(href={ url })
mk-time(time={ p.created_at })
div.body
div.text
a.reply(if={ p.reply_to }): i.fa.fa-reply
span@text
a.quote(if={ p.repost != null }) RP:
div.media(if={ p.media })
mk-images-viewer(images={ p.media })
div.repost(if={ p.repost })
i.fa.fa-quote-right.fa-flip-horizontal
mk-post-preview.repost(post={ p.repost })
footer
button(onclick={ reply }, title='返信')
i.fa.fa-reply
p.count(if={ p.replies_count > 0 }) { p.replies_count }
button(onclick={ repost }, title='Repost')
i.fa.fa-retweet
p.count(if={ p.repost_count > 0 }) { p.repost_count }
button(class={ liked: p.is_liked }, onclick={ like }, title='善哉')
i.fa.fa-thumbs-o-up
p.count(if={ p.likes_count > 0 }) { p.likes_count }
button(onclick={ NotImplementedException }): i.fa.fa-ellipsis-h
button(onclick={ toggle-detail }, title='詳細')
i.fa.fa-caret-down(if={ !is-detail-opened })
i.fa.fa-caret-up(if={ is-detail-opened })
div.detail(if={ is-detail-opened })
mk-post-status-graph(width='462', height='130', post={ p })
style.
display block
margin 0
padding 0
background #fff
&:focus
z-index 1
&:after
content ""
pointer-events none
position absolute
top 2px
right 2px
bottom 2px
left 2px
border 2px solid rgba($theme-color, 0.3)
border-radius 4px
> .repost
color #9dbb00
background linear-gradient(to bottom, #edfde2 0%, #fff 100%)
> p
<mk-timeline-post tabindex="-1" title="{ title }" onkeydown="{ onKeyDown }">
<div class="reply-to" if="{ p.reply_to }">
<mk-timeline-post-sub post="{ p.reply_to }"></mk-timeline-post-sub>
</div>
<div class="repost" if="{ isRepost }">
<p><a class="avatar-anchor" href="{ CONFIG.url + '/' + post.user.username }" data-user-preview="{ post.user_id }"><img class="avatar" src="{ post.user.avatar_url + '?thumbnail&amp;size=32' }" alt="avatar"/></a><i class="fa fa-retweet"></i><a class="name" href="{ CONFIG.url + '/' + post.user.username }" data-user-preview="{ post.user_id }">{ post.user.name }</a>がRepost</p>
<mk-time time="{ post.created_at }"></mk-time>
</div>
<article><a class="avatar-anchor" href="{ CONFIG.url + '/' + p.user.username }"><img class="avatar" src="{ p.user.avatar_url + '?thumbnail&amp;size=64' }" alt="avatar" data-user-preview="{ p.user.id }"/></a>
<div class="main">
<header><a class="name" href="{ CONFIG.url + '/' + p.user.username }" data-user-preview="{ p.user.id }">{ p.user.name }</a><span class="username">@{ p.user.username }</span><a class="created-at" href="{ url }">
<mk-time time="{ p.created_at }"></mk-time></a></header>
<div class="body">
<div class="text"><a class="reply" if="{ p.reply_to }"><i class="fa fa-reply"></i></a><span ref="text"></span><a class="quote" if="{ p.repost != null }">RP:</a></div>
<div class="media" if="{ p.media }">
<mk-images-viewer images="{ p.media }"></mk-images-viewer>
</div>
<div class="repost" if="{ p.repost }"><i class="fa fa-quote-right fa-flip-horizontal"></i>
<mk-post-preview class="repost" post="{ p.repost }"></mk-post-preview>
</div>
</div>
<footer>
<button onclick="{ reply }" title="返信"><i class="fa fa-reply"></i>
<p class="count" if="{ p.replies_count &gt; 0 }">{ p.replies_count }</p>
</button>
<button onclick="{ repost }" title="Repost"><i class="fa fa-retweet"></i>
<p class="count" if="{ p.repost_count &gt; 0 }">{ p.repost_count }</p>
</button>
<button class="{ liked: p.is_liked }" onclick="{ like }" title="善哉"><i class="fa fa-thumbs-o-up"></i>
<p class="count" if="{ p.likes_count &gt; 0 }">{ p.likes_count }</p>
</button>
<button onclick="{ NotImplementedException }"><i class="fa fa-ellipsis-h"></i></button>
<button onclick="{ toggleDetail }" title="詳細"><i class="fa fa-caret-down" if="{ !isDetailOpened }"></i><i class="fa fa-caret-up" if="{ isDetailOpened }"></i></button>
</footer>
</div>
</article>
<div class="detail" if="{ isDetailOpened }">
<mk-post-status-graph width="462" height="130" post="{ p }"></mk-post-status-graph>
</div>
<style type="stylus">
:scope
display block
margin 0
padding 16px 32px
line-height 28px
padding 0
background #fff
.avatar-anchor
display inline-block
&:focus
z-index 1
.avatar
vertical-align bottom
width 28px
height 28px
margin 0 8px 0 0
border-radius 6px
i
margin-right 4px
.name
font-weight bold
> mk-time
position absolute
top 16px
right 32px
font-size 0.9em
line-height 28px
& + article
padding-top 8px
> .reply-to
padding 0 16px
background rgba(0, 0, 0, 0.0125)
> mk-post-preview
background transparent
> article
padding 28px 32px 18px 32px
&:after
content ""
display block
clear both
&:hover
> .main > footer > button
color #888
> .avatar-anchor
display block
float left
margin 0 16px 0 0
> .avatar
display block
width 58px
height 58px
margin 0
border-radius 8px
vertical-align bottom
> .main
float left
width calc(100% - 74px)
> header
margin-bottom 4px
white-space nowrap
line-height 24px
> .name
display inline
margin 0
padding 0
color #777
font-size 1em
font-weight 700
text-align left
text-decoration none
&:hover
text-decoration underline
> .username
text-align left
margin 0 0 0 8px
color #ccc
> .created-at
&:after
content ""
pointer-events none
position absolute
top 0
right 0
font-size 0.9em
color #c0c0c0
top 2px
right 2px
bottom 2px
left 2px
border 2px solid rgba($theme-color, 0.3)
border-radius 4px
> .body
> .repost
color #9dbb00
background linear-gradient(to bottom, #edfde2 0%, #fff 100%)
> .text
cursor default
display block
> p
margin 0
padding 0
word-wrap break-word
font-size 1.1em
color #717171
padding 16px 32px
line-height 28px
mk-url-preview
margin-top 8px
.avatar-anchor
display inline-block
> .reply
margin-right 8px
color #717171
.avatar
vertical-align bottom
width 28px
height 28px
margin 0 8px 0 0
border-radius 6px
> .quote
margin-left 4px
font-style oblique
color #a0bf46
i
margin-right 4px
> .media
> img
display block
max-width 100%
.name
font-weight bold
> .repost
margin 8px 0
> mk-time
position absolute
top 16px
right 32px
font-size 0.9em
line-height 28px
> i:first-child
position absolute
top -8px
left -8px
z-index 1
color #c0dac6
font-size 28px
background #fff
& + article
padding-top 8px
> mk-post-preview
padding 16px
border dashed 1px #c0dac6
border-radius 8px
> .reply-to
padding 0 16px
background rgba(0, 0, 0, 0.0125)
> footer
> button
margin 0 28px 0 0
padding 0 8px
line-height 32px
font-size 1em
color #ddd
> mk-post-preview
background transparent
border none
cursor pointer
&:hover
color #666
> article
padding 28px 32px 18px 32px
> .count
display inline
margin 0 0 0 8px
color #999
&:after
content ""
display block
clear both
&.liked
color $theme-color
&:hover
> .main > footer > button
color #888
&:last-child
position absolute
right 0
> .avatar-anchor
display block
float left
margin 0 16px 0 0
> .avatar
display block
width 58px
height 58px
margin 0
border-radius 8px
vertical-align bottom
> .detail
padding-top 4px
background rgba(0, 0, 0, 0.0125)
> .main
float left
width calc(100% - 74px)
style(theme='dark').
background #0D0D0D
> header
margin-bottom 4px
white-space nowrap
line-height 24px
> article
> .name
display inline
margin 0
padding 0
color #777
font-size 1em
font-weight 700
text-align left
text-decoration none
&:hover
> .main > footer > button
color #eee
&:hover
text-decoration underline
> .main
> header
> .left
> .name
color #9e9c98
> .username
text-align left
margin 0 0 0 8px
color #ccc
> .username
color #41403f
> .created-at
position absolute
top 0
right 0
font-size 0.9em
color #c0c0c0
> .right
> .time
color #4e4d4b
> .body
> .body
> .text
color #9e9c98
> .text
cursor default
display block
margin 0
padding 0
word-wrap break-word
font-size 1.1em
color #717171
> footer
> button
color #9e9c98
mk-url-preview
margin-top 8px
&:hover
color #fff
> .reply
margin-right 8px
color #717171
> .count
color #eee
> .quote
margin-left 4px
font-style oblique
color #a0bf46
script.
@mixin \api
@mixin \text
@mixin \date-stringify
@mixin \user-preview
@mixin \NotImplementedException
> .media
> img
display block
max-width 100%
@post = @opts.post
@is-repost = @post.repost? and !@post.text?
@p = if @is-repost then @post.repost else @post
> .repost
margin 8px 0
@title = @date-stringify @p.created_at
> i:first-child
position absolute
top -8px
left -8px
z-index 1
color #c0dac6
font-size 28px
background #fff
@url = CONFIG.url + '/' + @p.user.username + '/' + @p.id
@is-detail-opened = false
> mk-post-preview
padding 16px
border dashed 1px #c0dac6
border-radius 8px
@on \mount ~>
if @p.text?
tokens = if @p._highlight?
then @analyze @p._highlight
else @analyze @p.text
> footer
> button
margin 0 28px 0 0
padding 0 8px
line-height 32px
font-size 1em
color #ddd
background transparent
border none
cursor pointer
@refs.text.innerHTML = if @p._highlight?
then @compile tokens, true, false
else @compile tokens
&:hover
color #666
@refs.text.children.for-each (e) ~>
if e.tag-name == \MK-URL
riot.mount e
> .count
display inline
margin 0 0 0 8px
color #999
# URLをプレビュー
tokens
.filter (t) -> t.type == \link
.map (t) ~>
@preview = @refs.text.append-child document.create-element \mk-url-preview
riot.mount @preview, do
url: t.content
&.liked
color $theme-color
@reply = ~>
form = document.body.append-child document.create-element \mk-post-form-window
riot.mount form, do
reply: @p
&:last-child
position absolute
right 0
margin 0
@repost = ~>
form = document.body.append-child document.create-element \mk-repost-form-window
riot.mount form, do
post: @p
> .detail
padding-top 4px
background rgba(0, 0, 0, 0.0125)
@like = ~>
if @p.is_liked
@api \posts/likes/delete do
post_id: @p.id
.then ~>
@p.is_liked = false
@update!
else
@api \posts/likes/create do
post_id: @p.id
.then ~>
@p.is_liked = true
@update!
</style>
<script>
@mixin \api
@mixin \text
@mixin \date-stringify
@mixin \user-preview
@mixin \NotImplementedException
@toggle-detail = ~>
@is-detail-opened = !@is-detail-opened
@update!
@post = @opts.post
@is-repost = @post.repost? and !@post.text?
@p = if @is-repost then @post.repost else @post
@on-key-down = (e) ~>
should-be-cancel = true
switch
| e.which == 38 or e.which == 74 or (e.which == 9 and e.shift-key) => # ↑, j or Shift+Tab
focus @root, (e) -> e.previous-element-sibling
| e.which == 40 or e.which == 75 or e.which == 9 => # ↓, k or Tab
focus @root, (e) -> e.next-element-sibling
| e.which == 81 or e.which == 69 => # q or e
@repost!
| e.which == 70 or e.which == 76 => # f or l
@like!
| e.which == 82 => # r
@reply!
| _ =>
should-be-cancel = false
@title = @date-stringify @p.created_at
if should-be-cancel
e.prevent-default!
@url = CONFIG.url + '/' + @p.user.username + '/' + @p.id
@is-detail-opened = false
function focus(el, fn)
target = fn el
if target?
if target.has-attribute \tabindex
target.focus!
@on \mount ~>
if @p.text?
tokens = if @p._highlight?
then @analyze @p._highlight
else @analyze @p.text
@refs.text.innerHTML = if @p._highlight?
then @compile tokens, true, false
else @compile tokens
@refs.text.children.for-each (e) ~>
if e.tag-name == \MK-URL
riot.mount e
# URLをプレビュー
tokens
.filter (t) -> t.type == \link
.map (t) ~>
@preview = @refs.text.append-child document.create-element \mk-url-preview
riot.mount @preview, do
url: t.content
@reply = ~>
form = document.body.append-child document.create-element \mk-post-form-window
riot.mount form, do
reply: @p
@repost = ~>
form = document.body.append-child document.create-element \mk-repost-form-window
riot.mount form, do
post: @p
@like = ~>
if @p.is_liked
@api \posts/likes/delete do
post_id: @p.id
.then ~>
@p.is_liked = false
@update!
else
focus target, fn
@api \posts/likes/create do
post_id: @p.id
.then ~>
@p.is_liked = true
@update!
@toggle-detail = ~>
@is-detail-opened = !@is-detail-opened
@update!
@on-key-down = (e) ~>
should-be-cancel = true
switch
| e.which == 38 or e.which == 74 or (e.which == 9 and e.shift-key) => # ↑, j or Shift+Tab
focus @root, (e) -> e.previous-element-sibling
| e.which == 40 or e.which == 75 or e.which == 9 => # ↓, k or Tab
focus @root, (e) -> e.next-element-sibling
| e.which == 81 or e.which == 69 => # q or e
@repost!
| e.which == 70 or e.which == 76 => # f or l
@like!
| e.which == 82 => # r
@reply!
| _ =>
should-be-cancel = false
if should-be-cancel
e.prevent-default!
function focus(el, fn)
target = fn el
if target?
if target.has-attribute \tabindex
target.focus!
else
focus target, fn
</script>
</mk-timeline-post>

View File

@ -1,86 +1,79 @@
mk-timeline
virtual(each={ post, i in posts })
mk-timeline-post(post={ post })
p.date(if={ i != posts.length - 1 && post._date != posts[i + 1]._date })
span
i.fa.fa-angle-up
| { post._datetext }
span
i.fa.fa-angle-down
| { posts[i + 1]._datetext }
footer(data-yield='footer')
| <yield from="footer"/>
<mk-timeline>
<virtual each="{ post, i in posts }">
<mk-timeline-post post="{ post }"></mk-timeline-post>
<p class="date" if="{ i != posts.length - 1 &amp;&amp; post._date != posts[i + 1]._date }"><span><i class="fa fa-angle-up"></i>{ post._datetext }</span><span><i class="fa fa-angle-down"></i>{ posts[i + 1]._datetext }</span></p>
</virtual>
<footer data-yield="footer"><yield from="footer"/></footer>
<style type="stylus">
:scope
display block
style.
display block
> mk-timeline-post
border-bottom solid 1px #eaeaea
> mk-timeline-post
border-bottom solid 1px #eaeaea
&:first-child
border-top-left-radius 4px
border-top-right-radius 4px
&:first-child
border-top-left-radius 4px
border-top-right-radius 4px
&:last-of-type
border-bottom none
&:last-of-type
border-bottom none
> .date
display block
margin 0
line-height 32px
font-size 14px
text-align center
color #aaa
background #fdfdfd
border-bottom solid 1px #eaeaea
> .date
display block
margin 0
line-height 32px
font-size 14px
text-align center
color #aaa
background #fdfdfd
border-bottom solid 1px #eaeaea
span
margin 0 16px
span
margin 0 16px
i
margin-right 8px
i
margin-right 8px
> footer
padding 16px
text-align center
color #ccc
border-top solid 1px #eaeaea
border-bottom-left-radius 4px
border-bottom-right-radius 4px
> footer
padding 16px
text-align center
color #ccc
border-top solid 1px #eaeaea
border-bottom-left-radius 4px
border-bottom-right-radius 4px
</style>
<script>
@posts = []
style(theme='dark').
> mk-timeline-post
border-bottom-color #222221
script.
@posts = []
@set-posts = (posts) ~>
@posts = posts
@update!
@prepend-posts = (posts) ~>
posts.for-each (post) ~>
@posts.push post
@set-posts = (posts) ~>
@posts = posts
@update!
@add-post = (post) ~>
@posts.unshift post
@update!
@prepend-posts = (posts) ~>
posts.for-each (post) ~>
@posts.push post
@update!
@clear = ~>
@posts = []
@update!
@add-post = (post) ~>
@posts.unshift post
@update!
@focus = ~>
@root.children.0.focus!
@clear = ~>
@posts = []
@update!
@on \update ~>
@posts.for-each (post) ~>
date = (new Date post.created_at).get-date!
month = (new Date post.created_at).get-month! + 1
post._date = date
post._datetext = month + '月 ' + date + '日'
@focus = ~>
@root.children.0.focus!
@tail = ~>
@posts[@posts.length - 1]
@on \update ~>
@posts.for-each (post) ~>
date = (new Date post.created_at).get-date!
month = (new Date post.created_at).get-month! + 1
post._date = date
post._datetext = month + '月 ' + date + '日'
@tail = ~>
@posts[@posts.length - 1]
</script>
</mk-timeline>

View File

@ -1,219 +1,212 @@
mk-ui-header-account
button.header(data-active={ is-open.toString() }, onclick={ toggle })
span.username
| { I.username }
i.fa.fa-angle-down(if={ !is-open })
i.fa.fa-angle-up(if={ is-open })
img.avatar(src={ I.avatar_url + '?thumbnail&size=64' }, alt='avatar')
div.menu(if={ is-open })
ul
li: a(href={ '/' + I.username })
i.fa.fa-user
| プロフィール
i.fa.fa-angle-right
li(onclick={ drive }): p
i.fa.fa-cloud
| ドライブ
i.fa.fa-angle-right
li: a(href='/i>mentions')
i.fa.fa-at
| あなた宛て
i.fa.fa-angle-right
ul
li(onclick={ settings }): p
i.fa.fa-cog
| 設定
i.fa.fa-angle-right
ul
li(onclick={ signout }): p
i(class='fa fa-power-off')
| サインアウト
i.fa.fa-angle-right
style.
display block
float left
> .header
display block
margin 0
padding 0
color #9eaba8
border none
background transparent
cursor pointer
*
pointer-events none
&:hover
color darken(#9eaba8, 20%)
&:active
color darken(#9eaba8, 30%)
&[data-active='true']
color darken(#9eaba8, 20%)
> .avatar
$saturate = 150%
filter saturate($saturate)
-webkit-filter saturate($saturate)
-moz-filter saturate($saturate)
-ms-filter saturate($saturate)
> .username
<mk-ui-header-account>
<button class="header" data-active="{ isOpen.toString() }" onclick="{ toggle }"><span class="username">{ I.username }<i class="fa fa-angle-down" if="{ !isOpen }"></i><i class="fa fa-angle-up" if="{ isOpen }"></i></span><img class="avatar" src="{ I.avatar_url + '?thumbnail&amp;size=64' }" alt="avatar"/></button>
<div class="menu" if="{ isOpen }">
<ul>
<li><a href="{ '/' + I.username }"><i class="fa fa-user"></i>プロフィール<i class="fa fa-angle-right"></i></a></li>
<li onclick="{ drive }">
<p><i class="fa fa-cloud"></i>ドライブ<i class="fa fa-angle-right"></i></p>
</li>
<li><a href="/i&gt;mentions"><i class="fa fa-at"></i>あなた宛て<i class="fa fa-angle-right"></i></a></li>
</ul>
<ul>
<li onclick="{ settings }">
<p><i class="fa fa-cog"></i>設定<i class="fa fa-angle-right"></i></p>
</li>
</ul>
<ul>
<li onclick="{ signout }">
<p><i class="fa fa-power-off"></i>サインアウト<i class="fa fa-angle-right"></i></p>
</li>
</ul>
</div>
<style type="stylus">
:scope
display block
float left
margin 0 12px 0 16px
max-width 16em
line-height 48px
font-weight bold
font-family Meiryo, sans-serif
text-decoration none
i
margin-left 8px
> .avatar
display block
float left
min-width 32px
max-width 32px
min-height 32px
max-height 32px
margin 8px 8px 8px 0
border-radius 4px
transition filter 100ms ease
> .menu
display block
position absolute
top 56px
right -2px
width 230px
font-size 0.8em
background #fff
border-radius 4px
box-shadow 0 1px 4px rgba(0, 0, 0, 0.25)
&:before
content ""
pointer-events none
display block
position absolute
top -28px
right 12px
border-top solid 14px transparent
border-right solid 14px transparent
border-bottom solid 14px rgba(0, 0, 0, 0.1)
border-left solid 14px transparent
&:after
content ""
pointer-events none
display block
position absolute
top -27px
right 12px
border-top solid 14px transparent
border-right solid 14px transparent
border-bottom solid 14px #fff
border-left solid 14px transparent
ul
display block
margin 10px 0
padding 0
list-style none
& + ul
padding-top 10px
border-top solid 1px #eee
> li
> .header
display block
margin 0
padding 0
color #9eaba8
border none
background transparent
cursor pointer
> a
> p
*
pointer-events none
&:hover
color darken(#9eaba8, 20%)
&:active
color darken(#9eaba8, 30%)
&[data-active='true']
color darken(#9eaba8, 20%)
> .avatar
$saturate = 150%
filter saturate($saturate)
-webkit-filter saturate($saturate)
-moz-filter saturate($saturate)
-ms-filter saturate($saturate)
> .username
display block
z-index 1
padding 0 28px
margin 0
line-height 40px
color #868C8C
cursor pointer
float left
margin 0 12px 0 16px
max-width 16em
line-height 48px
font-weight bold
font-family Meiryo, sans-serif
text-decoration none
*
pointer-events none
i
margin-left 8px
> i:first-of-type
margin-right 6px
> .avatar
display block
float left
min-width 32px
max-width 32px
min-height 32px
max-height 32px
margin 8px 8px 8px 0
border-radius 4px
transition filter 100ms ease
> i:last-of-type
> .menu
display block
position absolute
top 56px
right -2px
width 230px
font-size 0.8em
background #fff
border-radius 4px
box-shadow 0 1px 4px rgba(0, 0, 0, 0.25)
&:before
content ""
pointer-events none
display block
position absolute
top -28px
right 12px
border-top solid 14px transparent
border-right solid 14px transparent
border-bottom solid 14px rgba(0, 0, 0, 0.1)
border-left solid 14px transparent
&:after
content ""
pointer-events none
display block
position absolute
top -27px
right 12px
border-top solid 14px transparent
border-right solid 14px transparent
border-bottom solid 14px #fff
border-left solid 14px transparent
ul
display block
margin 10px 0
padding 0
list-style none
& + ul
padding-top 10px
border-top solid 1px #eee
> li
display block
position absolute
top 0
right 8px
z-index 1
padding 0 20px
font-size 1.2em
line-height 40px
margin 0
padding 0
&:hover, &:active
text-decoration none
background $theme-color
color $theme-color-foreground
> a
> p
display block
z-index 1
padding 0 28px
margin 0
line-height 40px
color #868C8C
cursor pointer
script.
@mixin \i
@mixin \signout
*
pointer-events none
@is-open = false
> i:first-of-type
margin-right 6px
@on \before-unmount ~>
@close!
> i:last-of-type
display block
position absolute
top 0
right 8px
z-index 1
padding 0 20px
font-size 1.2em
line-height 40px
@toggle = ~>
if @is-open
@close!
else
@open!
&:hover, &:active
text-decoration none
background $theme-color
color $theme-color-foreground
@open = ~>
@is-open = true
@update!
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.add-event-listener \mousedown @mousedown
</style>
<script>
@mixin \i
@mixin \signout
@close = ~>
@is-open = false
@update!
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.remove-event-listener \mousedown @mousedown
@mousedown = (e) ~>
e.prevent-default!
if (!contains @root, e.target) and (@root != e.target)
@on \before-unmount ~>
@close!
return false
@drive = ~>
@close!
riot.mount document.body.append-child document.create-element \mk-drive-browser-window
@toggle = ~>
if @is-open
@close!
else
@open!
@settings = ~>
@close!
riot.mount document.body.append-child document.create-element \mk-settings-window
@open = ~>
@is-open = true
@update!
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.add-event-listener \mousedown @mousedown
function contains(parent, child)
node = child.parent-node
while node?
if node == parent
return true
node = node.parent-node
return false
@close = ~>
@is-open = false
@update!
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.remove-event-listener \mousedown @mousedown
@mousedown = (e) ~>
e.prevent-default!
if (!contains @root, e.target) and (@root != e.target)
@close!
return false
@drive = ~>
@close!
riot.mount document.body.append-child document.create-element \mk-drive-browser-window
@settings = ~>
@close!
riot.mount document.body.append-child document.create-element \mk-settings-window
function contains(parent, child)
node = child.parent-node
while node?
if node == parent
return true
node = node.parent-node
return false
</script>
</mk-ui-header-account>

View File

@ -1,82 +1,87 @@
mk-ui-header-clock
div.header
time@time
div.content
mk-analog-clock
<mk-ui-header-clock>
<div class="header">
<time ref="time"></time>
</div>
<div class="content">
<mk-analog-clock></mk-analog-clock>
</div>
<style type="stylus">
:scope
display inline-block
overflow visible
style.
display inline-block
overflow visible
> .header
padding 0 12px
text-align center
font-size 0.5em
> .header
padding 0 12px
text-align center
font-size 0.5em
&, *
cursor: default
&, *
cursor: default
&:hover
background #899492
&:hover
background #899492
& + .content
visibility visible
& + .content
visibility visible
> time
color #fff !important
> time
color #fff !important
*
color #fff !important
*
color #fff !important
&:after
content ""
display block
clear both
&:after
content ""
display block
clear both
> time
display table-cell
vertical-align middle
height 48px
color #9eaba8
> time
display table-cell
vertical-align middle
height 48px
color #9eaba8
> .yyyymmdd
opacity 0.7
> .yyyymmdd
opacity 0.7
> .content
visibility hidden
display block
position absolute
top auto
right 0
z-index 3
margin 0
padding 0
width 256px
background #899492
> .content
visibility hidden
display block
position absolute
top auto
right 0
z-index 3
margin 0
padding 0
width 256px
background #899492
</style>
<script>
@draw = ~>
now = new Date!
script.
@draw = ~>
now = new Date!
yyyy = now.get-full-year!
mm = (\0 + (now.get-month! + 1)).slice -2
dd = (\0 + now.get-date!).slice -2
yyyymmdd = "<span class='yyyymmdd'>#yyyy/#mm/#dd</span>"
yyyy = now.get-full-year!
mm = (\0 + (now.get-month! + 1)).slice -2
dd = (\0 + now.get-date!).slice -2
yyyymmdd = "<span class='yyyymmdd'>#yyyy/#mm/#dd</span>"
hh = (\0 + now.get-hours!).slice -2
mm = (\0 + now.get-minutes!).slice -2
hhmm = "<span class='hhmm'>#hh:#mm</span>"
hh = (\0 + now.get-hours!).slice -2
mm = (\0 + now.get-minutes!).slice -2
hhmm = "<span class='hhmm'>#hh:#mm</span>"
if now.get-seconds! % 2 == 0
hhmm .= replace \: '<span style=\'visibility:visible\'>:</span>'
else
hhmm .= replace \: '<span style=\'visibility:hidden\'>:</span>'
if now.get-seconds! % 2 == 0
hhmm .= replace \: '<span style=\'visibility:visible\'>:</span>'
else
hhmm .= replace \: '<span style=\'visibility:hidden\'>:</span>'
@refs.time.innerHTML = "#yyyymmdd<br>#hhmm"
@refs.time.innerHTML = "#yyyymmdd<br>#hhmm"
@on \mount ~>
@draw!
@clock = set-interval @draw, 1000ms
@on \mount ~>
@draw!
@clock = set-interval @draw, 1000ms
@on \unmount ~>
clear-interval @clock
@on \unmount ~>
clear-interval @clock
</script>
</mk-ui-header-clock>

View File

@ -1,113 +1,113 @@
mk-ui-header-nav: ul(if={ SIGNIN })
li.home(class={ active: page == 'home' }): a(href={ CONFIG.url })
i.fa.fa-home
p ホーム
li.messaging: a(onclick={ messaging })
i.fa.fa-comments
p メッセージ
i.fa.fa-circle(if={ has-unread-messaging-messages })
li.info: a(href='https://twitter.com/misskey_xyz', target='_blank')
i.fa.fa-info
p お知らせ
li.tv: a(href='https://misskey.tk', target='_blank')
i.fa.fa-television
p MisskeyTV™
style.
display inline-block
margin 0
padding 0
line-height 3rem
vertical-align top
> ul
display inline-block
margin 0
padding 0
vertical-align top
line-height 3rem
list-style none
> li
display inline-block
vertical-align top
height 48px
line-height 48px
&.active
> a
border-bottom solid 3px $theme-color
> a
<mk-ui-header-nav>
<ul if="{ SIGNIN }">
<li class="home { active: page == 'home' }"><a href="{ CONFIG.url }"><i class="fa fa-home"></i>
<p>ホーム</p></a></li>
<li class="messaging"><a onclick="{ messaging }"><i class="fa fa-comments"></i>
<p>メッセージ</p><i class="fa fa-circle" if="{ hasUnreadMessagingMessages }"></i></a></li>
<li class="info"><a href="https://twitter.com/misskey_xyz" target="_blank"><i class="fa fa-info"></i>
<p>お知らせ</p></a></li>
<li class="tv"><a href="https://misskey.tk" target="_blank"><i class="fa fa-television"></i>
<p>MisskeyTV™</p></a></li>
<style type="stylus">
:scope
display inline-block
z-index 1
height 100%
padding 0 24px
font-size 1em
font-variant small-caps
color #9eaba8
text-decoration none
transition none
cursor pointer
margin 0
padding 0
line-height 3rem
vertical-align top
*
pointer-events none
&:hover
color darken(#9eaba8, 20%)
text-decoration none
> i:first-child
margin-right 8px
> i:last-child
margin-left 5px
vertical-align super
font-size 10px
color $theme-color
@media (max-width 1100px)
margin-left -5px
> p
display inline
> ul
display inline-block
margin 0
padding 0
vertical-align top
line-height 3rem
list-style none
@media (max-width 1100px)
display none
> li
display inline-block
vertical-align top
height 48px
line-height 48px
@media (max-width 700px)
padding 0 12px
&.active
> a
border-bottom solid 3px $theme-color
script.
@mixin \i
@mixin \api
@mixin \stream
> a
display inline-block
z-index 1
height 100%
padding 0 24px
font-size 1em
font-variant small-caps
color #9eaba8
text-decoration none
transition none
cursor pointer
@page = @opts.page
*
pointer-events none
@on \mount ~>
@stream.on \read_all_messaging_messages @on-read-all-messaging-messages
@stream.on \unread_messaging_message @on-unread-messaging-message
&:hover
color darken(#9eaba8, 20%)
text-decoration none
# Fetch count of unread messaging messages
@api \messaging/unread
.then (count) ~>
if count.count > 0
> i:first-child
margin-right 8px
> i:last-child
margin-left 5px
vertical-align super
font-size 10px
color $theme-color
@media (max-width 1100px)
margin-left -5px
> p
display inline
margin 0
@media (max-width 1100px)
display none
@media (max-width 700px)
padding 0 12px
</style>
<script>
@mixin \i
@mixin \api
@mixin \stream
@page = @opts.page
@on \mount ~>
@stream.on \read_all_messaging_messages @on-read-all-messaging-messages
@stream.on \unread_messaging_message @on-unread-messaging-message
# Fetch count of unread messaging messages
@api \messaging/unread
.then (count) ~>
if count.count > 0
@has-unread-messaging-messages = true
@update!
@on \unmount ~>
@stream.off \read_all_messaging_messages @on-read-all-messaging-messages
@stream.off \unread_messaging_message @on-unread-messaging-message
@on-read-all-messaging-messages = ~>
@has-unread-messaging-messages = false
@update!
@on-unread-messaging-message = ~>
@has-unread-messaging-messages = true
@update!
@on \unmount ~>
@stream.off \read_all_messaging_messages @on-read-all-messaging-messages
@stream.off \unread_messaging_message @on-unread-messaging-message
@on-read-all-messaging-messages = ~>
@has-unread-messaging-messages = false
@update!
@on-unread-messaging-message = ~>
@has-unread-messaging-messages = true
@update!
@messaging = ~>
riot.mount document.body.append-child document.create-element \mk-messaging-window
@messaging = ~>
riot.mount document.body.append-child document.create-element \mk-messaging-window
</script>
</ul>
</mk-ui-header-nav>

View File

@ -1,111 +1,114 @@
mk-ui-header-notifications
button.header(data-active={ is-open }, onclick={ toggle })
i.fa.fa-bell-o
div.notifications(if={ is-open })
mk-notifications
style.
display block
float left
> .header
display block
margin 0
padding 0
width 32px
color #9eaba8
border none
background transparent
cursor pointer
*
pointer-events none
&:hover
color darken(#9eaba8, 20%)
&:active
color darken(#9eaba8, 30%)
&[data-active='true']
color darken(#9eaba8, 20%)
> i
font-size 1.2em
line-height 48px
> .notifications
display block
position absolute
top 56px
right -72px
width 300px
background #fff
border-radius 4px
box-shadow 0 1px 4px rgba(0, 0, 0, 0.25)
&:before
content ""
pointer-events none
<mk-ui-header-notifications>
<button class="header" data-active="{ isOpen }" onclick="{ toggle }"><i class="fa fa-bell-o"></i></button>
<div class="notifications" if="{ isOpen }">
<mk-notifications></mk-notifications>
</div>
<style type="stylus">
:scope
display block
position absolute
top -28px
right 74px
border-top solid 14px transparent
border-right solid 14px transparent
border-bottom solid 14px rgba(0, 0, 0, 0.1)
border-left solid 14px transparent
float left
&:after
content ""
pointer-events none
display block
position absolute
top -27px
right 74px
border-top solid 14px transparent
border-right solid 14px transparent
border-bottom solid 14px #fff
border-left solid 14px transparent
> .header
display block
margin 0
padding 0
width 32px
color #9eaba8
border none
background transparent
cursor pointer
> mk-notifications
max-height 350px
font-size 1rem
overflow auto
*
pointer-events none
script.
@is-open = false
&:hover
color darken(#9eaba8, 20%)
@toggle = ~>
if @is-open
@close!
else
@open!
&:active
color darken(#9eaba8, 30%)
@open = ~>
@is-open = true
@update!
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.add-event-listener \mousedown @mousedown
&[data-active='true']
color darken(#9eaba8, 20%)
@close = ~>
> i
font-size 1.2em
line-height 48px
> .notifications
display block
position absolute
top 56px
right -72px
width 300px
background #fff
border-radius 4px
box-shadow 0 1px 4px rgba(0, 0, 0, 0.25)
&:before
content ""
pointer-events none
display block
position absolute
top -28px
right 74px
border-top solid 14px transparent
border-right solid 14px transparent
border-bottom solid 14px rgba(0, 0, 0, 0.1)
border-left solid 14px transparent
&:after
content ""
pointer-events none
display block
position absolute
top -27px
right 74px
border-top solid 14px transparent
border-right solid 14px transparent
border-bottom solid 14px #fff
border-left solid 14px transparent
> mk-notifications
max-height 350px
font-size 1rem
overflow auto
</style>
<script>
@is-open = false
@update!
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.remove-event-listener \mousedown @mousedown
@mousedown = (e) ~>
e.prevent-default!
if (!contains @root, e.target) and (@root != e.target)
@close!
return false
@toggle = ~>
if @is-open
@close!
else
@open!
function contains(parent, child)
node = child.parent-node
while node?
if node == parent
return true
node = node.parent-node
return false
@open = ~>
@is-open = true
@update!
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.add-event-listener \mousedown @mousedown
@close = ~>
@is-open = false
@update!
all = document.query-selector-all 'body *'
Array.prototype.for-each.call all, (el) ~>
el.remove-event-listener \mousedown @mousedown
@mousedown = (e) ~>
e.prevent-default!
if (!contains @root, e.target) and (@root != e.target)
@close!
return false
function contains(parent, child)
node = child.parent-node
while node?
if node == parent
return true
node = node.parent-node
return false
</script>
</mk-ui-header-notifications>

View File

@ -1,39 +1,41 @@
mk-ui-header-post-button
button(onclick={ post }, title='新規投稿')
i.fa.fa-pencil-square-o
<mk-ui-header-post-button>
<button onclick="{ post }" title="新規投稿"><i class="fa fa-pencil-square-o"></i></button>
<style type="stylus">
:scope
display inline-block
padding 8px
height 100%
vertical-align top
style.
display inline-block
padding 8px
height 100%
vertical-align top
> button
display inline-block
margin 0
padding 0 10px
height 100%
font-size 1.2em
font-weight normal
text-decoration none
color $theme-color-foreground
background $theme-color !important
outline none
border none
border-radius 2px
transition background 0.1s ease
cursor pointer
> button
display inline-block
margin 0
padding 0 10px
height 100%
font-size 1.2em
font-weight normal
text-decoration none
color $theme-color-foreground
background $theme-color !important
outline none
border none
border-radius 2px
transition background 0.1s ease
cursor pointer
*
pointer-events none
*
pointer-events none
&:hover
background lighten($theme-color, 10%) !important
&:hover
background lighten($theme-color, 10%) !important
&:active
background darken($theme-color, 10%) !important
transition background 0s ease
&:active
background darken($theme-color, 10%) !important
transition background 0s ease
script.
@post = (e) ~>
@parent.parent.open-post-form!
</style>
<script>
@post = (e) ~>
@parent.parent.open-post-form!
</script>
</mk-ui-header-post-button>

View File

@ -1,37 +1,41 @@
mk-ui-header-search
form.search(onsubmit={ onsubmit })
input@q(type='search', placeholder!='&#xf002; 検索')
div.result
<mk-ui-header-search>
<form class="search" onsubmit="{ onsubmit }">
<input ref="q" type="search" placeholder="&#xf002; 検索"/>
<div class="result"></div>
</form>
<style type="stylus">
:scope
style.
> form
display block
float left
> form
display block
float left
> input
user-select text
cursor auto
margin 0
padding 6px 18px
width 14em
height 48px
font-size 1em
line-height calc(48px - 12px)
background transparent
outline none
//border solid 1px #ddd
border none
border-radius 0
transition color 0.5s ease, border 0.5s ease
font-family FontAwesome, sans-serif
> input
user-select text
cursor auto
margin 0
padding 6px 18px
width 14em
height 48px
font-size 1em
line-height calc(48px - 12px)
background transparent
outline none
//border solid 1px #ddd
border none
border-radius 0
transition color 0.5s ease, border 0.5s ease
font-family FontAwesome, sans-serif
&::-webkit-input-placeholder
color #9eaba8
&::-webkit-input-placeholder
color #9eaba8
</style>
<script>
@mixin \page
script.
@mixin \page
@onsubmit = (e) ~>
e.prevent-default!
@page '/search:' + @refs.q.value
@onsubmit = (e) ~>
e.prevent-default!
@page '/search:' + @refs.q.value
</script>
</mk-ui-header-search>

Some files were not shown because too many files have changed in this diff Show More