diff --git a/gulpfile.ts b/gulpfile.ts index 5246705a11..677225c398 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -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; - } -} diff --git a/src/web/app/auth/tags/form.tag b/src/web/app/auth/tags/form.tag index f5b1555554..21c2339bc7 100644 --- a/src/web/app/auth/tags/form.tag +++ b/src/web/app/auth/tags/form.tag @@ -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&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> diff --git a/src/web/app/auth/tags/index.tag b/src/web/app/auth/tags/index.tag index b7017daec6..d4818b9bfd 100644 --- a/src/web/app/auth/tags/index.tag +++ b/src/web/app/auth/tags/index.tag @@ -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 && !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> diff --git a/src/web/app/common/tags/copyright.tag b/src/web/app/common/tags/copyright.tag index 0fccf375e8..c5041935f4 100644 --- a/src/web/app/common/tags/copyright.tag +++ b/src/web/app/common/tags/copyright.tag @@ -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> diff --git a/src/web/app/common/tags/core-error.tag b/src/web/app/common/tags/core-error.tag index 19ef68bea6..0473884497 100644 --- a/src/web/app/common/tags/core-error.tag +++ b/src/web/app/common/tags/core-error.tag @@ -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> diff --git a/src/web/app/common/tags/ellipsis.tag b/src/web/app/common/tags/ellipsis.tag index 47eca62acd..71755dd8f3 100644 --- a/src/web/app/common/tags/ellipsis.tag +++ b/src/web/app/common/tags/ellipsis.tag @@ -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> diff --git a/src/web/app/common/tags/file-type-icon.tag b/src/web/app/common/tags/file-type-icon.tag index 68b8f95ad7..4569fe81f1 100644 --- a/src/web/app/common/tags/file-type-icon.tag +++ b/src/web/app/common/tags/file-type-icon.tag @@ -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> diff --git a/src/web/app/common/tags/forkit.tag b/src/web/app/common/tags/forkit.tag index 7205fbe76b..5e44055455 100644 --- a/src/web/app/common/tags/forkit.tag +++ b/src/web/app/common/tags/forkit.tag @@ -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> diff --git a/src/web/app/common/tags/introduction.tag b/src/web/app/common/tags/introduction.tag index 99df485674..cfeeb24ace 100644 --- a/src/web/app/common/tags/introduction.tag +++ b/src/web/app/common/tags/introduction.tag @@ -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> diff --git a/src/web/app/common/tags/number.tag b/src/web/app/common/tags/number.tag index 589c747b35..3b9879655e 100644 --- a/src/web/app/common/tags/number.tag +++ b/src/web/app/common/tags/number.tag @@ -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> diff --git a/src/web/app/common/tags/raw.tag b/src/web/app/common/tags/raw.tag index 131826e597..ee7318a9f2 100644 --- a/src/web/app/common/tags/raw.tag +++ b/src/web/app/common/tags/raw.tag @@ -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> diff --git a/src/web/app/common/tags/ripple-string.tag b/src/web/app/common/tags/ripple-string.tag index 3be6903369..2afd2b9ff3 100644 --- a/src/web/app/common/tags/ripple-string.tag +++ b/src/web/app/common/tags/ripple-string.tag @@ -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> diff --git a/src/web/app/common/tags/signin.tag b/src/web/app/common/tags/signin.tag index 6f4013b1cb..dc5faca08d 100644 --- a/src/web/app/common/tags/signin.tag +++ b/src/web/app/common/tags/signin.tag @@ -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> diff --git a/src/web/app/common/tags/signup.tag b/src/web/app/common/tags/signup.tag index 9b28d7d1ff..c07b27fb19 100644 --- a/src/web/app/common/tags/signup.tag +++ b/src/web/app/common/tags/signup.tag @@ -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 != '' && username-state != 'invalidFormat' && username-state != 'minRange' && 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> diff --git a/src/web/app/common/tags/special-message.tag b/src/web/app/common/tags/special-message.tag index 5a6d5787ea..ffba09c2da 100644 --- a/src/web/app/common/tags/special-message.tag +++ b/src/web/app/common/tags/special-message.tag @@ -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 && d == 1 }">Happy New Year! </p> + <p if="{ m == 12 && 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> diff --git a/src/web/app/common/tags/time.tag b/src/web/app/common/tags/time.tag index 52ad89a44f..5456adb0b6 100644 --- a/src/web/app/common/tags/time.tag +++ b/src/web/app/common/tags/time.tag @@ -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> diff --git a/src/web/app/common/tags/uploader.tag b/src/web/app/common/tags/uploader.tag index 6d4e9b6363..6a081ddaf0 100644 --- a/src/web/app/common/tags/uploader.tag +++ b/src/web/app/common/tags/uploader.tag @@ -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 > 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 && 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 && 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> diff --git a/src/web/app/common/tags/url-preview.tag b/src/web/app/common/tags/url-preview.tag index 605d26bc67..860d4d547f 100644 --- a/src/web/app/common/tags/url-preview.tag +++ b/src/web/app/common/tags/url-preview.tag @@ -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> diff --git a/src/web/app/common/tags/url.tag b/src/web/app/common/tags/url.tag index 18892e8108..be7db32c5f 100644 --- a/src/web/app/common/tags/url.tag +++ b/src/web/app/common/tags/url.tag @@ -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> diff --git a/src/web/app/desktop/tags/analog-clock.tag b/src/web/app/desktop/tags/analog-clock.tag index a4cfe5726c..c84accb057 100644 --- a/src/web/app/desktop/tags/analog-clock.tag +++ b/src/web/app/desktop/tags/analog-clock.tag @@ -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> diff --git a/src/web/app/desktop/tags/autocomplete-suggestion.tag b/src/web/app/desktop/tags/autocomplete-suggestion.tag index 13d9df6914..ecebf26a32 100644 --- a/src/web/app/desktop/tags/autocomplete-suggestion.tag +++ b/src/web/app/desktop/tags/autocomplete-suggestion.tag @@ -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 > 0 }"> + <li each="{ users }" onclick="{ parent.onClick }" onkeydown="{ parent.onKeydown }" tabindex="-1"><img class="avatar" src="{ avatar_url + '?thumbnail&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> diff --git a/src/web/app/desktop/tags/big-follow-button.tag b/src/web/app/desktop/tags/big-follow-button.tag index 636853407c..37c67f07b2 100644 --- a/src/web/app/desktop/tags/big-follow-button.tag +++ b/src/web/app/desktop/tags/big-follow-button.tag @@ -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 && user.is_following }"><i class="fa fa-minus"></i>フォロー解除</span><span if="{ !wait && !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> diff --git a/src/web/app/desktop/tags/contextmenu.tag b/src/web/app/desktop/tags/contextmenu.tag index 7c3c7b8a24..c82a1e1e3a 100644 --- a/src/web/app/desktop/tags/contextmenu.tag +++ b/src/web/app/desktop/tags/contextmenu.tag @@ -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> diff --git a/src/web/app/desktop/tags/crop-window.tag b/src/web/app/desktop/tags/crop-window.tag index 16e1a72b3a..768c76d952 100644 --- a/src/web/app/desktop/tags/crop-window.tag +++ b/src/web/app/desktop/tags/crop-window.tag @@ -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&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> diff --git a/src/web/app/desktop/tags/debugger.tag b/src/web/app/desktop/tags/debugger.tag index e2b522cb00..9f9ff2cc4b 100644 --- a/src/web/app/desktop/tags/debugger.tag +++ b/src/web/app/desktop/tags/debugger.tag @@ -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> diff --git a/src/web/app/desktop/tags/detect-slow-internet-connection-notice.tag b/src/web/app/desktop/tags/detect-slow-internet-connection-notice.tag index f11a0c0857..09a746fb9b 100644 --- a/src/web/app/desktop/tags/detect-slow-internet-connection-notice.tag +++ b/src/web/app/desktop/tags/detect-slow-internet-connection-notice.tag @@ -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> diff --git a/src/web/app/desktop/tags/dialog.tag b/src/web/app/desktop/tags/dialog.tag index 88a461db84..d0aab4995c 100644 --- a/src/web/app/desktop/tags/dialog.tag +++ b/src/web/app/desktop/tags/dialog.tag @@ -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> diff --git a/src/web/app/desktop/tags/donation.tag b/src/web/app/desktop/tags/donation.tag index 9f8a1a6729..49ea8332d3 100644 --- a/src/web/app/desktop/tags/donation.tag +++ b/src/web/app/desktop/tags/donation.tag @@ -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> diff --git a/src/web/app/desktop/tags/drive/base-contextmenu.tag b/src/web/app/desktop/tags/drive/base-contextmenu.tag index c8b51009ea..d3a85e9157 100644 --- a/src/web/app/desktop/tags/drive/base-contextmenu.tag +++ b/src/web/app/desktop/tags/drive/base-contextmenu.tag @@ -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> diff --git a/src/web/app/desktop/tags/drive/browser-window.tag b/src/web/app/desktop/tags/drive/browser-window.tag index b3a5fc9a47..c7447a3c21 100644 --- a/src/web/app/desktop/tags/drive/browser-window.tag +++ b/src/web/app/desktop/tags/drive/browser-window.tag @@ -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> diff --git a/src/web/app/desktop/tags/drive/browser.tag b/src/web/app/desktop/tags/drive/browser.tag index 62e6425fe5..2bcb15f873 100644 --- a/src/web/app/desktop/tags/drive/browser.tag +++ b/src/web/app/desktop/tags/drive/browser.tag @@ -1,634 +1,637 @@ -mk-drive-browser - nav - div.path(oncontextmenu={ path-oncontextmenu }) - mk-drive-browser-nav-folder(class={ current: folder == null }, folder={ null }) - virtual(each={ folder in hierarchy-folders }) - span.separator: i.fa.fa-angle-right - mk-drive-browser-nav-folder(folder={ folder }) - span.separator(if={ folder != null }): i.fa.fa-angle-right - span.folder.current(if={ folder != null }) - | { folder.name } - input.search(type='search', placeholder!=' 検索') - div.main@main(class={ uploading: uploads.length > 0, loading: loading }, onmousedown={ onmousedown }, ondragover={ ondragover }, ondragenter={ ondragenter }, ondragleave={ ondragleave }, ondrop={ ondrop }, oncontextmenu={ oncontextmenu }) - div.selection@selection - div.contents@contents - div.folders@folders-container(if={ folders.length > 0 }) - virtual(each={ folder in folders }) - mk-drive-browser-folder.folder(folder={ folder }) - button(if={ more-folders }) - | もっと読み込む - div.files@files-container(if={ files.length > 0 }) - virtual(each={ file in files }) - mk-drive-browser-file.file(file={ file }) - button(if={ more-files }) - | もっと読み込む - div.empty(if={ files.length == 0 && folders.length == 0 && !loading }) - p(if={ draghover }) - | ドロップですか?いいですよ、ボクはカワイイですからね - p(if={ !draghover && folder == null }) - strong ドライブには何もありません。 - br - | 右クリックして「ファイルをアップロード」を選んだり、ファイルをドラッグ&ドロップすることでもアップロードできます。 - p(if={ !draghover && folder != null }) - | このフォルダーは空です - div.loading(if={ loading }). +<mk-drive-browser> + <nav> + <div class="path" oncontextmenu="{ pathOncontextmenu }"> + <mk-drive-browser-nav-folder class="{ current: folder == null }" folder="{ null }"></mk-drive-browser-nav-folder> + <virtual each="{ folder in hierarchyFolders }"><span class="separator"><i class="fa fa-angle-right"></i></span> + <mk-drive-browser-nav-folder folder="{ folder }"></mk-drive-browser-nav-folder> + </virtual><span class="separator" if="{ folder != null }"><i class="fa fa-angle-right"></i></span><span class="folder current" if="{ folder != null }">{ folder.name }</span> + </div> + <input class="search" type="search" placeholder=" 検索"/> + </nav> + <div class="main { uploading: uploads.length > 0, loading: loading }" ref="main" onmousedown="{ onmousedown }" ondragover="{ ondragover }" ondragenter="{ ondragenter }" ondragleave="{ ondragleave }" ondrop="{ ondrop }" oncontextmenu="{ oncontextmenu }"> + <div class="selection" ref="selection"></div> + <div class="contents" ref="contents"> + <div class="folders" ref="foldersContainer" if="{ folders.length > 0 }"> + <virtual each="{ folder in folders }"> + <mk-drive-browser-folder class="folder" folder="{ folder }"></mk-drive-browser-folder> + </virtual> + <button if="{ moreFolders }">もっと読み込む</button> + </div> + <div class="files" ref="filesContainer" if="{ files.length > 0 }"> + <virtual each="{ file in files }"> + <mk-drive-browser-file class="file" file="{ file }"></mk-drive-browser-file> + </virtual> + <button if="{ moreFiles }">もっと読み込む</button> + </div> + <div class="empty" if="{ files.length == 0 && folders.length == 0 && !loading }"> + <p if="{ draghover }">ドロップですか?いいですよ、ボクはカワイイですからね</p> + <p if="{ !draghover && folder == null }"><strong>ドライブには何もありません。</strong><br/>右クリックして「ファイルをアップロード」を選んだり、ファイルをドラッグ&ドロップすることでもアップロードできます。</p> + <p if="{ !draghover && folder != null }">このフォルダーは空です</p> + </div> + </div> + <div class="loading" if="{ loading }"> <div class="spinner"> <div class="dot1"></div> <div class="dot2"></div> </div> - div.dropzone(if={ draghover }) - mk-uploader@uploader - input@file-input(type='file', accept='*/*', multiple, tabindex='-1', onchange={ change-file-input }) + </div> + </div> + <div class="dropzone" if="{ draghover }"></div> + <mk-uploader ref="uploader"></mk-uploader> + <input ref="fileInput" type="file" accept="*/*" multiple="multiple" tabindex="-1" onchange="{ changeFileInput }"/> + <style type="stylus"> + :scope + display block -style. - display block + > nav + display block + z-index 2 + width 100% + overflow auto + font-size 0.9em + color #555 + background #fff + //border-bottom 1px solid #dfdfdf + box-shadow 0 1px 0 rgba(0, 0, 0, 0.05) - > nav - display block - z-index 2 - width 100% - overflow auto - font-size 0.9em - color #555 - background #fff - //border-bottom 1px solid #dfdfdf - box-shadow 0 1px 0 rgba(0, 0, 0, 0.05) + &, * + user-select none - &, * - user-select none + > .path + display inline-block + vertical-align bottom + margin 0 + padding 0 8px + width calc(100% - 200px) + line-height 38px + white-space nowrap - > .path - display inline-block - vertical-align bottom - margin 0 - padding 0 8px - width calc(100% - 200px) - line-height 38px - white-space nowrap + > * + display inline-block + margin 0 + padding 0 8px + line-height 38px + cursor pointer - > * - display inline-block - margin 0 - padding 0 8px - line-height 38px - cursor pointer + i + margin-right 4px - i - margin-right 4px + * + pointer-events none - * + &:hover + text-decoration underline + + &.current + font-weight bold + cursor default + + &:hover + text-decoration none + + &.separator + margin 0 + padding 0 + opacity 0.5 + cursor default + + > i + margin 0 + + > .search + display inline-block + vertical-align bottom + user-select text + cursor auto + margin 0 + padding 0 18px + width 200px + font-size 1em + line-height 38px + background transparent + outline none + //border solid 1px #ddd + border none + border-radius 0 + box-shadow none + transition color 0.5s ease, border 0.5s ease + font-family FontAwesome, sans-serif + + &[data-active='true'] + background #fff + + &::-webkit-input-placeholder, + &:-ms-input-placeholder, + &:-moz-placeholder + color $ui-controll-foreground-color + + > .main + padding 8px + height calc(100% - 38px) + overflow auto + + &, * + user-select none + + &.loading + cursor wait !important + + * + pointer-events none + + > .contents + opacity 0.5 + + &.uploading + height calc(100% - 38px - 100px) + + > .selection + display none + position absolute + z-index 128 + top 0 + left 0 + border solid 1px $theme-color + background rgba($theme-color, 0.5) pointer-events none - &:hover - text-decoration underline + > .contents - &.current - font-weight bold - cursor default + > .folders + &:after + content "" + display block + clear both - &:hover - text-decoration none + > .folder + float left - &.separator - margin 0 - padding 0 - opacity 0.5 - cursor default + > .files + &:after + content "" + display block + clear both - > i - margin 0 + > .file + float left - > .search - display inline-block - vertical-align bottom - user-select text - cursor auto - margin 0 - padding 0 18px - width 200px - font-size 1em - line-height 38px - background transparent - outline none - //border solid 1px #ddd - border none - border-radius 0 - box-shadow none - transition color 0.5s ease, border 0.5s ease - font-family FontAwesome, sans-serif + > .empty + padding 16px + text-align center + color #999 + pointer-events none - &[data-active='true'] + > p + margin 0 + + > .loading + .spinner + margin 100px auto + width 40px + height 40px + text-align center + + animation sk-rotate 2.0s infinite linear + + .dot1, .dot2 + width 60% + height 60% + display inline-block + position absolute + top 0 + background-color rgba(0, 0, 0, 0.3) + border-radius 100% + + animation sk-bounce 2.0s infinite ease-in-out + + .dot2 + top auto + bottom 0 + animation-delay -1.0s + + @keyframes sk-rotate { 100% { transform: rotate(360deg); }} + + @keyframes sk-bounce { + 0%, 100% { + transform: scale(0.0); + } 50% { + transform: scale(1.0); + } + } + + > .dropzone + position absolute + left 0 + top 38px + width 100% + height calc(100% - 38px) + border dashed 2px rgba($theme-color, 0.5) + pointer-events none + + > mk-uploader + height 100px + padding 16px background #fff - &::-webkit-input-placeholder, - &:-ms-input-placeholder, - &:-moz-placeholder - color $ui-controll-foreground-color + > input + display none - > .main - padding 8px - height calc(100% - 38px) - overflow auto + </style> + <script> + @mixin \api + @mixin \dialog + @mixin \input-dialog + @mixin \stream - &, * - user-select none + @files = [] + @folders = [] + @hierarchy-folders = [] - &.loading - cursor wait !important + @uploads = [] - * - pointer-events none + # 現在の階層(フォルダ) + # * null でルートを表す + @folder = null - > .contents - opacity 0.5 + @multiple = if @opts.multiple? then @opts.multiple else false - &.uploading - height calc(100% - 38px - 100px) + # ドロップされようとしているか + @draghover = false - > .selection - display none - position absolute - z-index 128 - top 0 - left 0 - border solid 1px $theme-color - background rgba($theme-color, 0.5) - pointer-events none + # 自信の所有するアイテムがドラッグをスタートさせたか + # (自分自身の階層にドロップできないようにするためのフラグ) + @is-drag-source = false - > .contents + @on \mount ~> + @refs.uploader.on \uploaded (file) ~> + @add-file file, true - > .folders - &:after - content "" - display block - clear both + @refs.uploader.on \change-uploads (uploads) ~> + @uploads = uploads + @update! - > .folder - float left + @stream.on \drive_file_created @on-stream-drive-file-created + @stream.on \drive_file_updated @on-stream-drive-file-updated + @stream.on \drive_folder_created @on-stream-drive-folder-created + @stream.on \drive_folder_updated @on-stream-drive-folder-updated - > .files - &:after - content "" - display block - clear both + # Riotのバグでnullを渡しても""になる + # https://github.com/riot/riot/issues/2080 + #if @opts.folder? + if @opts.folder? and @opts.folder != '' + @move @opts.folder + else + @load! - > .file - float left + @on \unmount ~> + @stream.off \drive_file_created @on-stream-drive-file-created + @stream.off \drive_file_updated @on-stream-drive-file-updated + @stream.off \drive_folder_created @on-stream-drive-folder-created + @stream.off \drive_folder_updated @on-stream-drive-folder-updated - > .empty - padding 16px - text-align center - color #999 - pointer-events none - - > p - margin 0 - - > .loading - .spinner - margin 100px auto - width 40px - height 40px - text-align center - - animation sk-rotate 2.0s infinite linear - - .dot1, .dot2 - width 60% - height 60% - display inline-block - position absolute - top 0 - background-color rgba(0, 0, 0, 0.3) - border-radius 100% - - animation sk-bounce 2.0s infinite ease-in-out - - .dot2 - top auto - bottom 0 - animation-delay -1.0s - - @keyframes sk-rotate { 100% { transform: rotate(360deg); }} - - @keyframes sk-bounce { - 0%, 100% { - transform: scale(0.0); - } 50% { - transform: scale(1.0); - } - } - - > .dropzone - position absolute - left 0 - top 38px - width 100% - height calc(100% - 38px) - border dashed 2px rgba($theme-color, 0.5) - pointer-events none - - > mk-uploader - height 100px - padding 16px - background #fff - - > input - display none - -script. - @mixin \api - @mixin \dialog - @mixin \input-dialog - @mixin \stream - - @files = [] - @folders = [] - @hierarchy-folders = [] - - @uploads = [] - - # 現在の階層(フォルダ) - # * null でルートを表す - @folder = null - - @multiple = if @opts.multiple? then @opts.multiple else false - - # ドロップされようとしているか - @draghover = false - - # 自信の所有するアイテムがドラッグをスタートさせたか - # (自分自身の階層にドロップできないようにするためのフラグ) - @is-drag-source = false - - @on \mount ~> - @refs.uploader.on \uploaded (file) ~> + @on-stream-drive-file-created = (file) ~> @add-file file, true - @refs.uploader.on \change-uploads (uploads) ~> - @uploads = uploads - @update! + @on-stream-drive-file-updated = (file) ~> + current = if @folder? then @folder.id else null + if current != file.folder_id + @remove-file file + else + @add-file file, true - @stream.on \drive_file_created @on-stream-drive-file-created - @stream.on \drive_file_updated @on-stream-drive-file-updated - @stream.on \drive_folder_created @on-stream-drive-folder-created - @stream.on \drive_folder_updated @on-stream-drive-folder-updated - - # Riotのバグでnullを渡しても""になる - # https://github.com/riot/riot/issues/2080 - #if @opts.folder? - if @opts.folder? and @opts.folder != '' - @move @opts.folder - else - @load! - - @on \unmount ~> - @stream.off \drive_file_created @on-stream-drive-file-created - @stream.off \drive_file_updated @on-stream-drive-file-updated - @stream.off \drive_folder_created @on-stream-drive-folder-created - @stream.off \drive_folder_updated @on-stream-drive-folder-updated - - @on-stream-drive-file-created = (file) ~> - @add-file file, true - - @on-stream-drive-file-updated = (file) ~> - current = if @folder? then @folder.id else null - if current != file.folder_id - @remove-file file - else - @add-file file, true - - @on-stream-drive-folder-created = (folder) ~> - @add-folder folder, true - - @on-stream-drive-folder-updated = (folder) ~> - current = if @folder? then @folder.id else null - if current != folder.parent_id - @remove-folder folder - else + @on-stream-drive-folder-created = (folder) ~> @add-folder folder, true - @onmousedown = (e) ~> - if (contains @refs.folders-container, e.target) or (contains @refs.files-container, e.target) - return true - - rect = @refs.main.get-bounding-client-rect! - - left = e.page-x + @refs.main.scroll-left - rect.left - window.page-x-offset - top = e.page-y + @refs.main.scroll-top - rect.top - window.page-y-offset - - move = (e) ~> - @refs.selection.style.display = \block - - cursor-x = e.page-x + @refs.main.scroll-left - rect.left - window.page-x-offset - cursor-y = e.page-y + @refs.main.scroll-top - rect.top - window.page-y-offset - w = cursor-x - left - h = cursor-y - top - - if w > 0 - @refs.selection.style.width = w + \px - @refs.selection.style.left = left + \px + @on-stream-drive-folder-updated = (folder) ~> + current = if @folder? then @folder.id else null + if current != folder.parent_id + @remove-folder folder else - @refs.selection.style.width = -w + \px - @refs.selection.style.left = cursor-x + \px + @add-folder folder, true - if h > 0 - @refs.selection.style.height = h + \px - @refs.selection.style.top = top + \px - else - @refs.selection.style.height = -h + \px - @refs.selection.style.top = cursor-y + \px + @onmousedown = (e) ~> + if (contains @refs.folders-container, e.target) or (contains @refs.files-container, e.target) + return true - up = (e) ~> - document.document-element.remove-event-listener \mousemove move - document.document-element.remove-event-listener \mouseup up + rect = @refs.main.get-bounding-client-rect! - @refs.selection.style.display = \none + left = e.page-x + @refs.main.scroll-left - rect.left - window.page-x-offset + top = e.page-y + @refs.main.scroll-top - rect.top - window.page-y-offset - document.document-element.add-event-listener \mousemove move - document.document-element.add-event-listener \mouseup up + move = (e) ~> + @refs.selection.style.display = \block - @path-oncontextmenu = (e) ~> - e.prevent-default! - e.stop-immediate-propagation! - return false + cursor-x = e.page-x + @refs.main.scroll-left - rect.left - window.page-x-offset + cursor-y = e.page-y + @refs.main.scroll-top - rect.top - window.page-y-offset + w = cursor-x - left + h = cursor-y - top - @ondragover = (e) ~> - e.prevent-default! - e.stop-propagation! + if w > 0 + @refs.selection.style.width = w + \px + @refs.selection.style.left = left + \px + else + @refs.selection.style.width = -w + \px + @refs.selection.style.left = cursor-x + \px - # ドラッグ元が自分自身の所有するアイテムかどうか - if !@is-drag-source - # ドラッグされてきたものがファイルだったら - if e.data-transfer.effect-allowed == \all - e.data-transfer.drop-effect = \copy - else - e.data-transfer.drop-effect = \move - @draghover = true - else - # 自分自身にはドロップさせない - e.data-transfer.drop-effect = \none - return false + if h > 0 + @refs.selection.style.height = h + \px + @refs.selection.style.top = top + \px + else + @refs.selection.style.height = -h + \px + @refs.selection.style.top = cursor-y + \px - @ondragenter = (e) ~> - e.prevent-default! - if !@is-drag-source - @draghover = true + up = (e) ~> + document.document-element.remove-event-listener \mousemove move + document.document-element.remove-event-listener \mouseup up - @ondragleave = (e) ~> - @draghover = false + @refs.selection.style.display = \none - @ondrop = (e) ~> - e.prevent-default! - e.stop-propagation! + document.document-element.add-event-listener \mousemove move + document.document-element.add-event-listener \mouseup up - @draghover = false - - # ドロップされてきたものがファイルだったら - if e.data-transfer.files.length > 0 - Array.prototype.for-each.call e.data-transfer.files, (file) ~> - @upload file, @folder + @path-oncontextmenu = (e) ~> + e.prevent-default! + e.stop-immediate-propagation! return false - # データ取得 - data = e.data-transfer.get-data 'text' - if !data? + @ondragover = (e) ~> + e.prevent-default! + e.stop-propagation! + + # ドラッグ元が自分自身の所有するアイテムかどうか + if !@is-drag-source + # ドラッグされてきたものがファイルだったら + if e.data-transfer.effect-allowed == \all + e.data-transfer.drop-effect = \copy + else + e.data-transfer.drop-effect = \move + @draghover = true + else + # 自分自身にはドロップさせない + e.data-transfer.drop-effect = \none return false - # パース - obj = JSON.parse data + @ondragenter = (e) ~> + e.prevent-default! + if !@is-drag-source + @draghover = true - # (ドライブの)ファイルだったら - if obj.type == \file - file = obj.id - if (@files.some (f) ~> f.id == file) + @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, @folder return false - @remove-file file - @api \drive/files/update do - file_id: file - folder_id: if @folder? then @folder.id else \null - .then ~> - # something + + # データ取得 + data = e.data-transfer.get-data 'text' + if !data? + return false + + # パース + obj = JSON.parse data + + # (ドライブの)ファイルだったら + if obj.type == \file + file = obj.id + if (@files.some (f) ~> f.id == file) + return false + @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 + if (@folders.some (f) ~> f.id == folder) + return false + @remove-folder folder + @api \drive/folders/update do + folder_id: folder + parent_id: if @folder? then @folder.id else \null + .then ~> + # something + .catch (err) ~> + if err == 'detected-circular-definition' + @dialog do + '<i class="fa fa-exclamation-triangle"></i>操作を完了できません' + '移動先のフォルダーは、移動するフォルダーのサブフォルダーです。' + [ + text: \OK + ] + + return false + + @oncontextmenu = (e) ~> + e.prevent-default! + e.stop-immediate-propagation! + + ctx = document.body.append-child document.create-element \mk-drive-browser-base-contextmenu + ctx = riot.mount ctx, do + browser: @ + ctx = ctx.0 + ctx.open do + x: e.page-x - window.page-x-offset + y: e.page-y - window.page-y-offset + + return false + + @select-local-file = ~> + @refs.file-input.click! + + @create-folder = ~> + name <~ @input-dialog do + 'フォルダー作成' + 'フォルダー名' + null + + @api \drive/folders/create do + name: name + folder_id: if @folder? then @folder.id else undefined + .then (folder) ~> + @add-folder folder, true + @update! + .catch (err) ~> + console.error err + + @change-file-input = ~> + files = @refs.file-input.files + for i from 0 to files.length - 1 + file = files.item i + @upload file, @folder + + @upload = (file, folder) ~> + if folder? and typeof folder == \object + folder = folder.id + @refs.uploader.upload file, folder + + @get-selection = ~> + @files.filter (file) -> file._selected + + @new-window = (folder-id) ~> + browser = document.body.append-child document.create-element \mk-drive-browser-window + riot.mount browser, do + folder: folder-id + + @move = (target-folder) ~> + if target-folder? and typeof target-folder == \object + target-folder = target-folder.id + + if target-folder == null + @go-root! + return + + @loading = true + @update! + + @api \drive/folders/show do + folder_id: target-folder + .then (folder) ~> + @folder = folder + @hierarchy-folders = [] + + x = (f) ~> + @hierarchy-folders.unshift f + if f.parent? + x f.parent + + if folder.parent? + x folder.parent + + @update! + @load! + .catch (err, text-status) -> + console.error err + + @add-folder = (folder, unshift = false) ~> + current = if @folder? then @folder.id else null + if current != folder.parent_id + return + + if (@folders.some (f) ~> f.id == folder.id) + exist = (@folders.map (f) -> f.id).index-of folder.id + @folders[exist] = folder + @update! + return + + if unshift + @folders.unshift folder + else + @folders.push folder + + @update! + + @add-file = (file, unshift = false) ~> + current = if @folder? then @folder.id else null + if current != file.folder_id + return + + if (@files.some (f) ~> f.id == file.id) + exist = (@files.map (f) -> f.id).index-of file.id + @files[exist] = file + @update! + return + + if unshift + @files.unshift file + else + @files.push file + + @update! + + @remove-folder = (folder) ~> + if typeof folder == \object + folder = folder.id + @folders = @folders.filter (f) -> f.id != folder + @update! + + @remove-file = (file) ~> + if typeof file == \object + file = file.id + @files = @files.filter (f) -> f.id != file + @update! + + @go-root = ~> + if @folder != null + @folder = null + @hierarchy-folders = [] + @update! + @load! + + @load = ~> + @folders = [] + @files = [] + @more-folders = false + @more-files = false + @loading = true + @update! + + load-folders = null + load-files = null + + folders-max = 30 + files-max = 30 + + # フォルダ一覧取得 + @api \drive/folders do + folder_id: if @folder? then @folder.id else null + limit: folders-max + 1 + .then (folders) ~> + if folders.length == folders-max + 1 + @more-folders = true + folders.pop! + load-folders := folders + complete! .catch (err, text-status) ~> console.error err - # (ドライブの)フォルダーだったら - else if obj.type == \folder - folder = obj.id - # 移動先が自分自身ならreject - if @folder? and folder == @folder.id - return false - if (@folders.some (f) ~> f.id == folder) - return false - @remove-folder folder - @api \drive/folders/update do - folder_id: folder - parent_id: if @folder? then @folder.id else \null - .then ~> - # something - .catch (err) ~> - if err == 'detected-circular-definition' - @dialog do - '<i class="fa fa-exclamation-triangle"></i>操作を完了できません' - '移動先のフォルダーは、移動するフォルダーのサブフォルダーです。' - [ - text: \OK - ] + # ファイル一覧取得 + @api \drive/files do + folder_id: if @folder? then @folder.id else null + limit: files-max + 1 + .then (files) ~> + if files.length == files-max + 1 + @more-files = true + files.pop! + load-files := files + complete! + .catch (err, text-status) ~> + console.error err - return false + flag = false + complete = ~> + if flag + load-folders.for-each (folder) ~> + @add-folder folder + load-files.for-each (file) ~> + @add-file file + @loading = false + @update! + else + flag := true - @oncontextmenu = (e) ~> - e.prevent-default! - e.stop-immediate-propagation! - - ctx = document.body.append-child document.create-element \mk-drive-browser-base-contextmenu - ctx = riot.mount ctx, do - browser: @ - ctx = ctx.0 - ctx.open do - x: e.page-x - window.page-x-offset - y: e.page-y - window.page-y-offset - - return false - - @select-local-file = ~> - @refs.file-input.click! - - @create-folder = ~> - name <~ @input-dialog do - 'フォルダー作成' - 'フォルダー名' - null - - @api \drive/folders/create do - name: name - folder_id: if @folder? then @folder.id else undefined - .then (folder) ~> - @add-folder folder, true - @update! - .catch (err) ~> - console.error err - - @change-file-input = ~> - files = @refs.file-input.files - for i from 0 to files.length - 1 - file = files.item i - @upload file, @folder - - @upload = (file, folder) ~> - if folder? and typeof folder == \object - folder = folder.id - @refs.uploader.upload file, folder - - @get-selection = ~> - @files.filter (file) -> file._selected - - @new-window = (folder-id) ~> - browser = document.body.append-child document.create-element \mk-drive-browser-window - riot.mount browser, do - folder: folder-id - - @move = (target-folder) ~> - if target-folder? and typeof target-folder == \object - target-folder = target-folder.id - - if target-folder == null - @go-root! - return - - @loading = true - @update! - - @api \drive/folders/show do - folder_id: target-folder - .then (folder) ~> - @folder = folder - @hierarchy-folders = [] - - x = (f) ~> - @hierarchy-folders.unshift f - if f.parent? - x f.parent - - if folder.parent? - x folder.parent - - @update! - @load! - .catch (err, text-status) -> - console.error err - - @add-folder = (folder, unshift = false) ~> - current = if @folder? then @folder.id else null - if current != folder.parent_id - return - - if (@folders.some (f) ~> f.id == folder.id) - exist = (@folders.map (f) -> f.id).index-of folder.id - @folders[exist] = folder - @update! - return - - if unshift - @folders.unshift folder - else - @folders.push folder - - @update! - - @add-file = (file, unshift = false) ~> - current = if @folder? then @folder.id else null - if current != file.folder_id - return - - if (@files.some (f) ~> f.id == file.id) - exist = (@files.map (f) -> f.id).index-of file.id - @files[exist] = file - @update! - return - - if unshift - @files.unshift file - else - @files.push file - - @update! - - @remove-folder = (folder) ~> - if typeof folder == \object - folder = folder.id - @folders = @folders.filter (f) -> f.id != folder - @update! - - @remove-file = (file) ~> - if typeof file == \object - file = file.id - @files = @files.filter (f) -> f.id != file - @update! - - @go-root = ~> - if @folder != null - @folder = null - @hierarchy-folders = [] - @update! - @load! - - @load = ~> - @folders = [] - @files = [] - @more-folders = false - @more-files = false - @loading = true - @update! - - load-folders = null - load-files = null - - folders-max = 30 - files-max = 30 - - # フォルダ一覧取得 - @api \drive/folders do - folder_id: if @folder? then @folder.id else null - limit: folders-max + 1 - .then (folders) ~> - if folders.length == folders-max + 1 - @more-folders = true - folders.pop! - load-folders := folders - complete! - .catch (err, text-status) ~> - console.error err - - # ファイル一覧取得 - @api \drive/files do - folder_id: if @folder? then @folder.id else null - limit: files-max + 1 - .then (files) ~> - if files.length == files-max + 1 - @more-files = true - files.pop! - load-files := files - complete! - .catch (err, text-status) ~> - console.error err - - flag = false - complete = ~> - if flag - load-folders.for-each (folder) ~> - @add-folder folder - load-files.for-each (file) ~> - @add-file file - @loading = false - @update! - else - flag := true - - function contains(parent, child) - node = child.parent-node - while node? - if node == parent - return true - node = node.parent-node - 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-drive-browser> diff --git a/src/web/app/desktop/tags/drive/file-contextmenu.tag b/src/web/app/desktop/tags/drive/file-contextmenu.tag index 7d7dca6c92..96779601db 100644 --- a/src/web/app/desktop/tags/drive/file-contextmenu.tag +++ b/src/web/app/desktop/tags/drive/file-contextmenu.tag @@ -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> diff --git a/src/web/app/desktop/tags/drive/file.tag b/src/web/app/desktop/tags/drive/file.tag index 1702bb6501..8daa54983d 100644 --- a/src/web/app/desktop/tags/drive/file.tag +++ b/src/web/app/desktop/tags/drive/file.tag @@ -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&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> diff --git a/src/web/app/desktop/tags/drive/folder-contextmenu.tag b/src/web/app/desktop/tags/drive/folder-contextmenu.tag index 67fb1047b7..eb50e51c68 100644 --- a/src/web/app/desktop/tags/drive/folder-contextmenu.tag +++ b/src/web/app/desktop/tags/drive/folder-contextmenu.tag @@ -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> diff --git a/src/web/app/desktop/tags/drive/folder.tag b/src/web/app/desktop/tags/drive/folder.tag index 0f3b06d543..ddeb21027b 100644 --- a/src/web/app/desktop/tags/drive/folder.tag +++ b/src/web/app/desktop/tags/drive/folder.tag @@ -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> diff --git a/src/web/app/desktop/tags/drive/nav-folder.tag b/src/web/app/desktop/tags/drive/nav-folder.tag index 398a26a80b..34d6efdf58 100644 --- a/src/web/app/desktop/tags/drive/nav-folder.tag +++ b/src/web/app/desktop/tags/drive/nav-folder.tag @@ -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> diff --git a/src/web/app/desktop/tags/ellipsis-icon.tag b/src/web/app/desktop/tags/ellipsis-icon.tag index 5d18bc0473..34731bb797 100644 --- a/src/web/app/desktop/tags/ellipsis-icon.tag +++ b/src/web/app/desktop/tags/ellipsis-icon.tag @@ -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> diff --git a/src/web/app/desktop/tags/follow-button.tag b/src/web/app/desktop/tags/follow-button.tag index 41bd1f0e12..300a5fe035 100644 --- a/src/web/app/desktop/tags/follow-button.tag +++ b/src/web/app/desktop/tags/follow-button.tag @@ -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 && user.is_following }"></i><i class="fa fa-plus" if="{ !wait && !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> diff --git a/src/web/app/desktop/tags/following-setuper.tag b/src/web/app/desktop/tags/following-setuper.tag index 9b75a251e0..6e8e40a2b1 100644 --- a/src/web/app/desktop/tags/following-setuper.tag +++ b/src/web/app/desktop/tags/following-setuper.tag @@ -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 && users.length > 0 }"> + <div class="user" each="{ users }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + username }"><img class="avatar" src="{ avatar_url + '?thumbnail&size=42' }" alt="" data-user-preview="{ id }"/></a> + <div class="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 && 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> diff --git a/src/web/app/desktop/tags/go-top.tag b/src/web/app/desktop/tags/go-top.tag index a11f4a3640..d43e68ea90 100644 --- a/src/web/app/desktop/tags/go-top.tag +++ b/src/web/app/desktop/tags/go-top.tag @@ -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> diff --git a/src/web/app/desktop/tags/home-widgets/broadcast.tag b/src/web/app/desktop/tags/home-widgets/broadcast.tag index 0e21adec48..dda71218ab 100644 --- a/src/web/app/desktop/tags/home-widgets/broadcast.tag +++ b/src/web/app/desktop/tags/home-widgets/broadcast.tag @@ -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> diff --git a/src/web/app/desktop/tags/home-widgets/calendar.tag b/src/web/app/desktop/tags/home-widgets/calendar.tag index 87c65729d3..affa55c96b 100644 --- a/src/web/app/desktop/tags/home-widgets/calendar.tag +++ b/src/web/app/desktop/tags/home-widgets/calendar.tag @@ -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> diff --git a/src/web/app/desktop/tags/home-widgets/donation.tag b/src/web/app/desktop/tags/home-widgets/donation.tag index a41bd9f8a4..01d9b20ea2 100644 --- a/src/web/app/desktop/tags/home-widgets/donation.tag +++ b/src/web/app/desktop/tags/home-widgets/donation.tag @@ -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> diff --git a/src/web/app/desktop/tags/home-widgets/mentions.tag b/src/web/app/desktop/tags/home-widgets/mentions.tag index 0f0cd0269d..81ceff6179 100644 --- a/src/web/app/desktop/tags/home-widgets/mentions.tag +++ b/src/web/app/desktop/tags/home-widgets/mentions.tag @@ -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> diff --git a/src/web/app/desktop/tags/home-widgets/nav.tag b/src/web/app/desktop/tags/home-widgets/nav.tag index 5b8e7e1b3c..7e153bc234 100644 --- a/src/web/app/desktop/tags/home-widgets/nav.tag +++ b/src/web/app/desktop/tags/home-widgets/nav.tag @@ -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> diff --git a/src/web/app/desktop/tags/home-widgets/notifications.tag b/src/web/app/desktop/tags/home-widgets/notifications.tag index 588a765d02..43baa01439 100644 --- a/src/web/app/desktop/tags/home-widgets/notifications.tag +++ b/src/web/app/desktop/tags/home-widgets/notifications.tag @@ -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> diff --git a/src/web/app/desktop/tags/home-widgets/photo-stream.tag b/src/web/app/desktop/tags/home-widgets/photo-stream.tag index b972706574..245427badf 100644 --- a/src/web/app/desktop/tags/home-widgets/photo-stream.tag +++ b/src/web/app/desktop/tags/home-widgets/photo-stream.tag @@ -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 && images.length > 0 }"> + <virtual each="{ image in images }"> + <div class="img" style="{ 'background-image: url(' + image.url + '?thumbnail&size=256)' }"></div> + </virtual> + </div> + <p class="empty" if="{ !initializing && 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> diff --git a/src/web/app/desktop/tags/home-widgets/profile.tag b/src/web/app/desktop/tags/home-widgets/profile.tag index ae8d43c645..24a0035c4c 100644 --- a/src/web/app/desktop/tags/home-widgets/profile.tag +++ b/src/web/app/desktop/tags/home-widgets/profile.tag @@ -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&size=256)' : '' }" onclick="{ setBanner }"></div><img class="avatar" src="{ I.avatar_url + '?thumbnail&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> diff --git a/src/web/app/desktop/tags/home-widgets/rss-reader.tag b/src/web/app/desktop/tags/home-widgets/rss-reader.tag index b9095fb2d2..bfd9d32e52 100644 --- a/src/web/app/desktop/tags/home-widgets/rss-reader.tag +++ b/src/web/app/desktop/tags/home-widgets/rss-reader.tag @@ -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> diff --git a/src/web/app/desktop/tags/home-widgets/timeline.tag b/src/web/app/desktop/tags/home-widgets/timeline.tag index ea2746d1ed..2bd9d104da 100644 --- a/src/web/app/desktop/tags/home-widgets/timeline.tag +++ b/src/web/app/desktop/tags/home-widgets/timeline.tag @@ -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> diff --git a/src/web/app/desktop/tags/home-widgets/tips.tag b/src/web/app/desktop/tags/home-widgets/tips.tag index 9c1aa33ec0..d85da0d295 100644 --- a/src/web/app/desktop/tags/home-widgets/tips.tag +++ b/src/web/app/desktop/tags/home-widgets/tips.tag @@ -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> diff --git a/src/web/app/desktop/tags/home-widgets/user-recommendation.tag b/src/web/app/desktop/tags/home-widgets/user-recommendation.tag index bfb90da065..bcf770ddab 100644 --- a/src/web/app/desktop/tags/home-widgets/user-recommendation.tag +++ b/src/web/app/desktop/tags/home-widgets/user-recommendation.tag @@ -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 && users.length != 0 }" each="{ _user in users }"><a class="avatar-anchor" href="{ CONFIG.url + '/' + _user.username }"><img class="avatar" src="{ _user.avatar_url + '?thumbnail&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 && 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> diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag index 1ae856a6b2..6d4a308ac2 100644 --- a/src/web/app/desktop/tags/home.tag +++ b/src/web/app/desktop/tags/home.tag @@ -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> diff --git a/src/web/app/desktop/tags/image-dialog.tag b/src/web/app/desktop/tags/image-dialog.tag index 6a3885d7c7..41ec876621 100644 --- a/src/web/app/desktop/tags/image-dialog.tag +++ b/src/web/app/desktop/tags/image-dialog.tag @@ -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> diff --git a/src/web/app/desktop/tags/images-viewer.tag b/src/web/app/desktop/tags/images-viewer.tag index a9939d67c4..c08c8d6926 100644 --- a/src/web/app/desktop/tags/images-viewer.tag +++ b/src/web/app/desktop/tags/images-viewer.tag @@ -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&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> diff --git a/src/web/app/desktop/tags/input-dialog.tag b/src/web/app/desktop/tags/input-dialog.tag index 62ec4f5177..a71ee58623 100644 --- a/src/web/app/desktop/tags/input-dialog.tag +++ b/src/web/app/desktop/tags/input-dialog.tag @@ -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 && 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> diff --git a/src/web/app/desktop/tags/list-user.tag b/src/web/app/desktop/tags/list-user.tag index 1058de22e0..ecf1e04d2e 100644 --- a/src/web/app/desktop/tags/list-user.tag +++ b/src/web/app/desktop/tags/list-user.tag @@ -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&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> diff --git a/src/web/app/desktop/tags/messaging/form.tag b/src/web/app/desktop/tags/messaging/form.tag index 12eb0cb40f..b521eb2fd3 100644 --- a/src/web/app/desktop/tags/messaging/form.tag +++ b/src/web/app/desktop/tags/messaging/form.tag @@ -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> diff --git a/src/web/app/desktop/tags/messaging/index.tag b/src/web/app/desktop/tags/messaging/index.tag index 9f57500b83..eeb92fc3f0 100644 --- a/src/web/app/desktop/tags/messaging/index.tag +++ b/src/web/app/desktop/tags/messaging/index.tag @@ -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 > 0 }"> + <li each="{ user in searchResult }"><a onclick="{ user._click }"><img class="avatar" src="{ user.avatar_url + '?thumbnail&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 > 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&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> diff --git a/src/web/app/desktop/tags/messaging/message.tag b/src/web/app/desktop/tags/messaging/message.tag index d7a2cc32a6..517689d132 100644 --- a/src/web/app/desktop/tags/messaging/message.tag +++ b/src/web/app/desktop/tags/messaging/message.tag @@ -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&size=64' }" alt=""/></a> + <div class="content-container"> + <div class="balloon"> + <p class="read" if="{ message.is_me && 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> diff --git a/src/web/app/desktop/tags/messaging/room-window.tag b/src/web/app/desktop/tags/messaging/room-window.tag index 673b11419a..46a2297f2a 100644 --- a/src/web/app/desktop/tags/messaging/room-window.tag +++ b/src/web/app/desktop/tags/messaging/room-window.tag @@ -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> diff --git a/src/web/app/desktop/tags/messaging/room.tag b/src/web/app/desktop/tags/messaging/room.tag index ca396d7418..929e62fc3a 100644 --- a/src/web/app/desktop/tags/messaging/room.tag +++ b/src/web/app/desktop/tags/messaging/room.tag @@ -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 && 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 && 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> diff --git a/src/web/app/desktop/tags/messaging/window.tag b/src/web/app/desktop/tags/messaging/window.tag index b6979b6244..17ebfd2280 100644 --- a/src/web/app/desktop/tags/messaging/window.tag +++ b/src/web/app/desktop/tags/messaging/window.tag @@ -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> diff --git a/src/web/app/desktop/tags/notifications.tag b/src/web/app/desktop/tags/notifications.tag index d47815a89b..b8f03fb6f2 100644 --- a/src/web/app/desktop/tags/notifications.tag +++ b/src/web/app/desktop/tags/notifications.tag @@ -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&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&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&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&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&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&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 && 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 && !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> diff --git a/src/web/app/desktop/tags/pages/entrance.tag b/src/web/app/desktop/tags/pages/entrance.tag index 5e18f616a3..4e1c5277a3 100644 --- a/src/web/app/desktop/tags/pages/entrance.tag +++ b/src/web/app/desktop/tags/pages/entrance.tag @@ -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> diff --git a/src/web/app/desktop/tags/pages/entrance/signin.tag b/src/web/app/desktop/tags/pages/entrance/signin.tag index 8ff39bc296..26bdb6898a 100644 --- a/src/web/app/desktop/tags/pages/entrance/signin.tag +++ b/src/web/app/desktop/tags/pages/entrance/signin.tag @@ -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&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> diff --git a/src/web/app/desktop/tags/pages/entrance/signup.tag b/src/web/app/desktop/tags/pages/entrance/signup.tag index 1b585f7000..2452b7d793 100644 --- a/src/web/app/desktop/tags/pages/entrance/signup.tag +++ b/src/web/app/desktop/tags/pages/entrance/signup.tag @@ -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> diff --git a/src/web/app/desktop/tags/pages/home.tag b/src/web/app/desktop/tags/pages/home.tag index 5d419a5802..3a0e713d30 100644 --- a/src/web/app/desktop/tags/pages/home.tag +++ b/src/web/app/desktop/tags/pages/home.tag @@ -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> diff --git a/src/web/app/desktop/tags/pages/not-found.tag b/src/web/app/desktop/tags/pages/not-found.tag index fe23cc6fa4..e3db8c0f70 100644 --- a/src/web/app/desktop/tags/pages/not-found.tag +++ b/src/web/app/desktop/tags/pages/not-found.tag @@ -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> diff --git a/src/web/app/desktop/tags/pages/post.tag b/src/web/app/desktop/tags/pages/post.tag index 81ab9ce006..f355770d38 100644 --- a/src/web/app/desktop/tags/pages/post.tag +++ b/src/web/app/desktop/tags/pages/post.tag @@ -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> diff --git a/src/web/app/desktop/tags/pages/search.tag b/src/web/app/desktop/tags/pages/search.tag index a7878ddc0f..a3b3bafd99 100644 --- a/src/web/app/desktop/tags/pages/search.tag +++ b/src/web/app/desktop/tags/pages/search.tag @@ -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> diff --git a/src/web/app/desktop/tags/pages/user.tag b/src/web/app/desktop/tags/pages/user.tag index d41093c298..d6587e8132 100644 --- a/src/web/app/desktop/tags/pages/user.tag +++ b/src/web/app/desktop/tags/pages/user.tag @@ -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> diff --git a/src/web/app/desktop/tags/post-detail-sub.tag b/src/web/app/desktop/tags/post-detail-sub.tag index b7aa745737..8b6411c12a 100644 --- a/src/web/app/desktop/tags/post-detail-sub.tag +++ b/src/web/app/desktop/tags/post-detail-sub.tag @@ -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&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&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> diff --git a/src/web/app/desktop/tags/post-detail.tag b/src/web/app/desktop/tags/post-detail.tag index e071b7c704..c395a44328 100644 --- a/src/web/app/desktop/tags/post-detail.tag +++ b/src/web/app/desktop/tags/post-detail.tag @@ -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 && p.reply_to.reply_to_id && 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&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&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&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 > 0 }">{ p.replies_count }</p> + </button> + <button onclick="{ repost }" title="Repost"><i class="fa fa-retweet"></i> + <p class="count" if="{ p.repost_count > 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 > 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 && reposts.length > 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&size=32' }" alt=""/></a></li> + </ol> + </div> + <div class="likes" if="{ likes && likes.length > 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&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> diff --git a/src/web/app/desktop/tags/post-form-window.tag b/src/web/app/desktop/tags/post-form-window.tag index 8727777944..753dea1adb 100644 --- a/src/web/app/desktop/tags/post-form-window.tag +++ b/src/web/app/desktop/tags/post-form-window.tag @@ -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> diff --git a/src/web/app/desktop/tags/post-form.tag b/src/web/app/desktop/tags/post-form.tag index 2248587885..3950d6cb07 100644 --- a/src/web/app/desktop/tags/post-form.tag +++ b/src/web/app/desktop/tags/post-form.tag @@ -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 + "?thumbnail&size=64" })" title="{ name }"></div><img class="remove" onclick="{ _remove }" src="/_/resources/desktop/remove.png" title="添付取り消し" alt=""/> + </li> + <li class="add" if="{ files.length < 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 > 300 }">のこり{ 300 - refs.text.value.length }文字</p> + <button class="{ wait: wait }" ref="submit" disabled="{ wait || (refs.text.value.length == 0 && 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> diff --git a/src/web/app/desktop/tags/post-preview.tag b/src/web/app/desktop/tags/post-preview.tag index f17b152801..4035261782 100644 --- a/src/web/app/desktop/tags/post-preview.tag +++ b/src/web/app/desktop/tags/post-preview.tag @@ -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&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> diff --git a/src/web/app/desktop/tags/post-status-graph.tag b/src/web/app/desktop/tags/post-status-graph.tag index ffb081e4f3..c6cdb53b47 100644 --- a/src/web/app/desktop/tags/post-status-graph.tag +++ b/src/web/app/desktop/tags/post-status-graph.tag @@ -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> diff --git a/src/web/app/desktop/tags/progress-dialog.tag b/src/web/app/desktop/tags/progress-dialog.tag index 7c042686e6..48b04d3442 100644 --- a/src/web/app/desktop/tags/progress-dialog.tag +++ b/src/web/app/desktop/tags/progress-dialog.tag @@ -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) && parent.value < parent.max }" value="{ isNaN(parent.value) ? 0 : parent.value }" max="{ parent.max }"></progress> + <div class="progress waiting" if="{ parent.value >= 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> diff --git a/src/web/app/desktop/tags/repost-form-window.tag b/src/web/app/desktop/tags/repost-form-window.tag index 40012f951f..a1008b475b 100644 --- a/src/web/app/desktop/tags/repost-form-window.tag +++ b/src/web/app/desktop/tags/repost-form-window.tag @@ -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> diff --git a/src/web/app/desktop/tags/repost-form.tag b/src/web/app/desktop/tags/repost-form.tag index 37fbad251d..0352cffc1b 100644 --- a/src/web/app/desktop/tags/repost-form.tag +++ b/src/web/app/desktop/tags/repost-form.tag @@ -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> diff --git a/src/web/app/desktop/tags/search-posts.tag b/src/web/app/desktop/tags/search-posts.tag index 9862ff6e4e..2d999e84ca 100644 --- a/src/web/app/desktop/tags/search-posts.tag +++ b/src/web/app/desktop/tags/search-posts.tag @@ -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> diff --git a/src/web/app/desktop/tags/search.tag b/src/web/app/desktop/tags/search.tag index aec426ac79..1a9703016d 100644 --- a/src/web/app/desktop/tags/search.tag +++ b/src/web/app/desktop/tags/search.tag @@ -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> diff --git a/src/web/app/desktop/tags/select-file-from-drive-window.tag b/src/web/app/desktop/tags/select-file-from-drive-window.tag index 5042944837..3293abb220 100644 --- a/src/web/app/desktop/tags/select-file-from-drive-window.tag +++ b/src/web/app/desktop/tags/select-file-from-drive-window.tag @@ -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 && parent.file.length > 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 && 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> diff --git a/src/web/app/desktop/tags/set-avatar-suggestion.tag b/src/web/app/desktop/tags/set-avatar-suggestion.tag index 68c9c310df..a8fc2a69ee 100644 --- a/src/web/app/desktop/tags/set-avatar-suggestion.tag +++ b/src/web/app/desktop/tags/set-avatar-suggestion.tag @@ -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> diff --git a/src/web/app/desktop/tags/set-banner-suggestion.tag b/src/web/app/desktop/tags/set-banner-suggestion.tag index bff0385803..ab4bbda047 100644 --- a/src/web/app/desktop/tags/set-banner-suggestion.tag +++ b/src/web/app/desktop/tags/set-banner-suggestion.tag @@ -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> diff --git a/src/web/app/desktop/tags/settings-window.tag b/src/web/app/desktop/tags/settings-window.tag index e259848718..6013f89673 100644 --- a/src/web/app/desktop/tags/settings-window.tag +++ b/src/web/app/desktop/tags/settings-window.tag @@ -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> diff --git a/src/web/app/desktop/tags/settings.tag b/src/web/app/desktop/tags/settings.tag index ac47fbf792..7e7811df21 100644 --- a/src/web/app/desktop/tags/settings.tag +++ b/src/web/app/desktop/tags/settings.tag @@ -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&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> diff --git a/src/web/app/desktop/tags/signin-history.tag b/src/web/app/desktop/tags/signin-history.tag index 311f8bfeda..bd6006965f 100644 --- a/src/web/app/desktop/tags/signin-history.tag +++ b/src/web/app/desktop/tags/signin-history.tag @@ -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> diff --git a/src/web/app/desktop/tags/stream-indicator.tag b/src/web/app/desktop/tags/stream-indicator.tag index 2eb5889ca6..4046f5fec4 100644 --- a/src/web/app/desktop/tags/stream-indicator.tag +++ b/src/web/app/desktop/tags/stream-indicator.tag @@ -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> diff --git a/src/web/app/desktop/tags/sub-post-content.tag b/src/web/app/desktop/tags/sub-post-content.tag index 976a6f398f..5b4497fda6 100644 --- a/src/web/app/desktop/tags/sub-post-content.tag +++ b/src/web/app/desktop/tags/sub-post-content.tag @@ -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> diff --git a/src/web/app/desktop/tags/timeline-post-sub.tag b/src/web/app/desktop/tags/timeline-post-sub.tag index 39b1ad7f71..a9a13e9f9c 100644 --- a/src/web/app/desktop/tags/timeline-post-sub.tag +++ b/src/web/app/desktop/tags/timeline-post-sub.tag @@ -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&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> diff --git a/src/web/app/desktop/tags/timeline-post.tag b/src/web/app/desktop/tags/timeline-post.tag index 8b90f0d013..77d695c365 100644 --- a/src/web/app/desktop/tags/timeline-post.tag +++ b/src/web/app/desktop/tags/timeline-post.tag @@ -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&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&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 > 0 }">{ p.replies_count }</p> + </button> + <button onclick="{ repost }" title="Repost"><i class="fa fa-retweet"></i> + <p class="count" if="{ p.repost_count > 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 > 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> diff --git a/src/web/app/desktop/tags/timeline.tag b/src/web/app/desktop/tags/timeline.tag index dfd1b7c14e..ce6c00d0ba 100644 --- a/src/web/app/desktop/tags/timeline.tag +++ b/src/web/app/desktop/tags/timeline.tag @@ -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 && 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> diff --git a/src/web/app/desktop/tags/ui-header-account.tag b/src/web/app/desktop/tags/ui-header-account.tag index ffb1eeec00..47351b5262 100644 --- a/src/web/app/desktop/tags/ui-header-account.tag +++ b/src/web/app/desktop/tags/ui-header-account.tag @@ -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&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>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> diff --git a/src/web/app/desktop/tags/ui-header-clock.tag b/src/web/app/desktop/tags/ui-header-clock.tag index 987907a684..da50d8401f 100644 --- a/src/web/app/desktop/tags/ui-header-clock.tag +++ b/src/web/app/desktop/tags/ui-header-clock.tag @@ -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> diff --git a/src/web/app/desktop/tags/ui-header-nav.tag b/src/web/app/desktop/tags/ui-header-nav.tag index 153c3137b4..8844307ae9 100644 --- a/src/web/app/desktop/tags/ui-header-nav.tag +++ b/src/web/app/desktop/tags/ui-header-nav.tag @@ -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> diff --git a/src/web/app/desktop/tags/ui-header-notifications.tag b/src/web/app/desktop/tags/ui-header-notifications.tag index 495aad5004..05d4f4c2cd 100644 --- a/src/web/app/desktop/tags/ui-header-notifications.tag +++ b/src/web/app/desktop/tags/ui-header-notifications.tag @@ -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> diff --git a/src/web/app/desktop/tags/ui-header-post-button.tag b/src/web/app/desktop/tags/ui-header-post-button.tag index 558c987619..79f836408a 100644 --- a/src/web/app/desktop/tags/ui-header-post-button.tag +++ b/src/web/app/desktop/tags/ui-header-post-button.tag @@ -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> diff --git a/src/web/app/desktop/tags/ui-header-search.tag b/src/web/app/desktop/tags/ui-header-search.tag index 24e4e44989..8803384938 100644 --- a/src/web/app/desktop/tags/ui-header-search.tag +++ b/src/web/app/desktop/tags/ui-header-search.tag @@ -1,37 +1,41 @@ -mk-ui-header-search - form.search(onsubmit={ onsubmit }) - input@q(type='search', placeholder!=' 検索') - div.result +<mk-ui-header-search> + <form class="search" onsubmit="{ onsubmit }"> + <input ref="q" type="search" placeholder=" 検索"/> + <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> diff --git a/src/web/app/desktop/tags/ui-header.tag b/src/web/app/desktop/tags/ui-header.tag index b02817cd84..4ec0ba183a 100644 --- a/src/web/app/desktop/tags/ui-header.tag +++ b/src/web/app/desktop/tags/ui-header.tag @@ -1,85 +1,85 @@ -mk-ui-header - mk-donation(if={ SIGNIN && !I.data.no_donation }) - mk-special-message - div.main - div.backdrop - div.main: div.container - div.left - mk-ui-header-nav(page={ opts.page }) - div.right - mk-ui-header-search - mk-ui-header-account(if={ SIGNIN }) - mk-ui-header-notifications(if={ SIGNIN }) - mk-ui-header-post-button(if={ SIGNIN }) - mk-ui-header-clock - -style. - display block - position fixed - top 0 - z-index 1024 - width 100% - box-shadow 0 1px 1px rgba(0, 0, 0, 0.075) - - > .main - - > .backdrop - position absolute +<mk-ui-header> + <mk-donation if="{ SIGNIN && !I.data.no_donation }"></mk-donation> + <mk-special-message></mk-special-message> + <div class="main"> + <div class="backdrop"></div> + <div class="main"> + <div class="container"> + <div class="left"> + <mk-ui-header-nav page="{ opts.page }"></mk-ui-header-nav> + </div> + <div class="right"> + <mk-ui-header-search></mk-ui-header-search> + <mk-ui-header-account if="{ SIGNIN }"></mk-ui-header-account> + <mk-ui-header-notifications if="{ SIGNIN }"></mk-ui-header-notifications> + <mk-ui-header-post-button if="{ SIGNIN }"></mk-ui-header-post-button> + <mk-ui-header-clock></mk-ui-header-clock> + </div> + </div> + </div> + </div> + <style type="stylus"> + :scope + display block + position fixed top 0 - z-index 1023 - width 100% - height 48px - backdrop-filter blur(12px) - //background-color rgba(255, 255, 255, 0.75) - background #fff - - &:after - content "" - display block - width 100% - height 48px - background-image url(/_/resources/desktop/header-logo.svg) - background-size 64px - background-position center - background-repeat no-repeat - - > .main z-index 1024 - margin 0 - padding 0 - background-clip content-box - font-size 0.9rem - user-select none + width 100% + box-shadow 0 1px 1px rgba(0, 0, 0, 0.075) - > .container - width 100% - max-width 1300px - margin 0 auto + > .main - &:after - content "" - display block - clear both - - > .left - float left - height 3rem - - > .right - float right + > .backdrop + position absolute + top 0 + z-index 1023 + width 100% height 48px + backdrop-filter blur(12px) + //background-color rgba(255, 255, 255, 0.75) + background #fff - @media (max-width 1100px) - > mk-ui-header-search - display none + &:after + content "" + display block + width 100% + height 48px + background-image url(/_/resources/desktop/header-logo.svg) + background-size 64px + background-position center + background-repeat no-repeat -style(theme='dark'). - box-shadow 0 1px 0 #222221 + > .main + z-index 1024 + margin 0 + padding 0 + background-clip content-box + font-size 0.9rem + user-select none - > .main + > .container + width 100% + max-width 1300px + margin 0 auto - > .backdrop - background #0D0D0D + &:after + content "" + display block + clear both -script. - @mixin \i + > .left + float left + height 3rem + + > .right + float right + height 48px + + @media (max-width 1100px) + > mk-ui-header-search + display none + + </style> + + <script>@mixin \i</script> +</mk-ui-header> diff --git a/src/web/app/desktop/tags/ui-notification.tag b/src/web/app/desktop/tags/ui-notification.tag index 6e5f948b88..aacf23cf50 100644 --- a/src/web/app/desktop/tags/ui-notification.tag +++ b/src/web/app/desktop/tags/ui-notification.tag @@ -1,41 +1,44 @@ -mk-ui-notification - p { opts.message } +<mk-ui-notification> + <p>{ opts.message }</p> + <style type="stylus"> + :scope + display block + position fixed + z-index 10000 + top -64px + left 0 + right 0 + margin 0 auto + width 500px + color rgba(#000, 0.6) + background rgba(#fff, 0.9) + border-radius 0 0 8px 8px + box-shadow 0 2px 4px rgba(#000, 0.2) -style. - display block - position fixed - z-index 10000 - top -64px - left 0 - right 0 - margin 0 auto - width 500px - color rgba(#000, 0.6) - background rgba(#fff, 0.9) - border-radius 0 0 8px 8px - box-shadow 0 2px 4px rgba(#000, 0.2) + > p + margin 0 + line-height 64px + text-align center - > p - margin 0 - line-height 64px - text-align center - -script. - @on \mount ~> - Velocity @root, { - top: \0px - } { - duration: 500ms - easing: \ease-out - } - - set-timeout ~> + </style> + <script> + @on \mount ~> Velocity @root, { - top: \-64px + top: \0px } { duration: 500ms easing: \ease-out - complete: ~> - @unmount! } - , 6000ms + + set-timeout ~> + Velocity @root, { + top: \-64px + } { + duration: 500ms + easing: \ease-out + complete: ~> + @unmount! + } + , 6000ms + </script> +</mk-ui-notification> diff --git a/src/web/app/desktop/tags/ui.tag b/src/web/app/desktop/tags/ui.tag index 6bced1f9e4..713db21d91 100644 --- a/src/web/app/desktop/tags/ui.tag +++ b/src/web/app/desktop/tags/ui.tag @@ -1,37 +1,37 @@ -mk-ui - div.global@global - mk-ui-header@header(page={ opts.page }) +<mk-ui> + <div class="global" ref="global"> + <mk-ui-header ref="header" page="{ opts.page }"></mk-ui-header> + <mk-set-avatar-suggestion if="{ SIGNIN && I.avatar_id == null }"></mk-set-avatar-suggestion> + <mk-set-banner-suggestion if="{ SIGNIN && I.banner_id == null }"></mk-set-banner-suggestion> + <div class="content"><yield /></div> + </div> + <mk-stream-indicator></mk-stream-indicator> + <style type="stylus"> + :scope + display block - mk-set-avatar-suggestion(if={ SIGNIN && I.avatar_id == null }) - mk-set-banner-suggestion(if={ SIGNIN && I.banner_id == null }) + </style> + <script> + @mixin \i - div.content - <yield /> + @open-post-form = ~> + riot.mount document.body.append-child document.create-element \mk-post-form-window - mk-stream-indicator + @set-root-layout = ~> + @root.style.padding-top = @refs.header.root.client-height + \px -style. - display block + @on \mount ~> + @set-root-layout! + document.add-event-listener \keydown @onkeydown -script. - @mixin \i + @on \unmount ~> + document.remove-event-listener \keydown @onkeydown - @open-post-form = ~> - riot.mount document.body.append-child document.create-element \mk-post-form-window - - @set-root-layout = ~> - @root.style.padding-top = @refs.header.root.client-height + \px - - @on \mount ~> - @set-root-layout! - document.add-event-listener \keydown @onkeydown - - @on \unmount ~> - document.remove-event-listener \keydown @onkeydown - - @onkeydown = (e) ~> - tag = e.target.tag-name.to-lower-case! - if tag != \input and tag != \textarea - if e.which == 80 or e.which == 78 # p or n - e.prevent-default! - @open-post-form! + @onkeydown = (e) ~> + tag = e.target.tag-name.to-lower-case! + if tag != \input and tag != \textarea + if e.which == 80 or e.which == 78 # p or n + e.prevent-default! + @open-post-form! + </script> +</mk-ui> diff --git a/src/web/app/desktop/tags/user-followers-window.tag b/src/web/app/desktop/tags/user-followers-window.tag index d18b04446c..c6899be46b 100644 --- a/src/web/app/desktop/tags/user-followers-window.tag +++ b/src/web/app/desktop/tags/user-followers-window.tag @@ -1,22 +1,19 @@ -mk-user-followers-window - mk-window(is-modal={ false }, width={ '400px' }, height={ '550px' }) - <yield to="header"> - img(src={ parent.user.avatar_url + '?thumbnail&size=64' }, alt='') - | { parent.user.name }のフォロワー - </yield> - <yield to="content"> - mk-user-followers(user={ parent.user }) - </yield> +<mk-user-followers-window> + <mk-window is-modal="{ false }" width="{ '400px' }" height="{ '550px' }"><yield to="header"><img src="{ parent.user.avatar_url + '?thumbnail&size=64' }" alt=""/>{ parent.user.name }のフォロワー</yield> +<yield to="content"> + <mk-user-followers user="{ parent.user }"></mk-user-followers></yield> + </mk-window> + <style type="stylus"> + :scope + > mk-window + [data-yield='header'] + > img + display inline-block + vertical-align bottom + height calc(100% - 10px) + margin 5px + border-radius 4px -style. - > mk-window - [data-yield='header'] - > img - display inline-block - vertical-align bottom - height calc(100% - 10px) - margin 5px - border-radius 4px - -script. - @user = @opts.user + </style> + <script>@user = @opts.user</script> +</mk-user-followers-window> diff --git a/src/web/app/desktop/tags/user-followers.tag b/src/web/app/desktop/tags/user-followers.tag index 52f9f43836..9f96b00177 100644 --- a/src/web/app/desktop/tags/user-followers.tag +++ b/src/web/app/desktop/tags/user-followers.tag @@ -1,19 +1,22 @@ -mk-user-followers - mk-users-list(fetch={ fetch }, count={ user.followers_count }, you-know-count={ user.followers_you_know_count }, no-users={ 'フォロワーはいないようです。' }) +<mk-user-followers> + <mk-users-list fetch="{ fetch }" count="{ user.followers_count }" you-know-count="{ user.followers_you_know_count }" no-users="{ 'フォロワーはいないようです。' }"></mk-users-list> + <style type="stylus"> + :scope + display block + height 100% -style. - display block - height 100% + </style> + <script> + @mixin \api -script. - @mixin \api + @user = @opts.user - @user = @opts.user - - @fetch = (iknow, limit, cursor, cb) ~> - @api \users/followers do - user_id: @user.id - iknow: iknow - limit: limit - cursor: if cursor? then cursor else undefined - .then cb + @fetch = (iknow, limit, cursor, cb) ~> + @api \users/followers do + user_id: @user.id + iknow: iknow + limit: limit + cursor: if cursor? then cursor else undefined + .then cb + </script> +</mk-user-followers> diff --git a/src/web/app/desktop/tags/user-following-window.tag b/src/web/app/desktop/tags/user-following-window.tag index 91f94f08d3..343820d4e0 100644 --- a/src/web/app/desktop/tags/user-following-window.tag +++ b/src/web/app/desktop/tags/user-following-window.tag @@ -1,22 +1,19 @@ -mk-user-following-window - mk-window(is-modal={ false }, width={ '400px' }, height={ '550px' }) - <yield to="header"> - img(src={ parent.user.avatar_url + '?thumbnail&size=64' }, alt='') - | { parent.user.name }のフォロー - </yield> - <yield to="content"> - mk-user-following(user={ parent.user }) - </yield> +<mk-user-following-window> + <mk-window is-modal="{ false }" width="{ '400px' }" height="{ '550px' }"><yield to="header"><img src="{ parent.user.avatar_url + '?thumbnail&size=64' }" alt=""/>{ parent.user.name }のフォロー</yield> +<yield to="content"> + <mk-user-following user="{ parent.user }"></mk-user-following></yield> + </mk-window> + <style type="stylus"> + :scope + > mk-window + [data-yield='header'] + > img + display inline-block + vertical-align bottom + height calc(100% - 10px) + margin 5px + border-radius 4px -style. - > mk-window - [data-yield='header'] - > img - display inline-block - vertical-align bottom - height calc(100% - 10px) - margin 5px - border-radius 4px - -script. - @user = @opts.user + </style> + <script>@user = @opts.user</script> +</mk-user-following-window> diff --git a/src/web/app/desktop/tags/user-following.tag b/src/web/app/desktop/tags/user-following.tag index 0a39f2e4b8..87b88b6cd2 100644 --- a/src/web/app/desktop/tags/user-following.tag +++ b/src/web/app/desktop/tags/user-following.tag @@ -1,19 +1,22 @@ -mk-user-following - mk-users-list(fetch={ fetch }, count={ user.following_count }, you-know-count={ user.following_you_know_count }, no-users={ 'フォロー中のユーザーはいないようです。' }) +<mk-user-following> + <mk-users-list fetch="{ fetch }" count="{ user.following_count }" you-know-count="{ user.following_you_know_count }" no-users="{ 'フォロー中のユーザーはいないようです。' }"></mk-users-list> + <style type="stylus"> + :scope + display block + height 100% -style. - display block - height 100% + </style> + <script> + @mixin \api -script. - @mixin \api + @user = @opts.user - @user = @opts.user - - @fetch = (iknow, limit, cursor, cb) ~> - @api \users/following do - user_id: @user.id - iknow: iknow - limit: limit - cursor: if cursor? then cursor else undefined - .then cb + @fetch = (iknow, limit, cursor, cb) ~> + @api \users/following do + user_id: @user.id + iknow: iknow + limit: limit + cursor: if cursor? then cursor else undefined + .then cb + </script> +</mk-user-following> diff --git a/src/web/app/desktop/tags/user-friends-graph.tag b/src/web/app/desktop/tags/user-friends-graph.tag index 47c3a15613..13c0bc2c38 100644 --- a/src/web/app/desktop/tags/user-friends-graph.tag +++ b/src/web/app/desktop/tags/user-friends-graph.tag @@ -1,64 +1,67 @@ -mk-user-friends-graph - canvas@canv(width='750', height='250') +<mk-user-friends-graph> + <canvas ref="canv" width="750" height="250"></canvas> + <style type="stylus"> + :scope + display block + width 750px + height 250px -style. - display block - width 750px - height 250px + </style> + <script> + @mixin \api + @mixin \is-promise -script. - @mixin \api - @mixin \is-promise + @user = null + @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user - @user = null - @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user + @on \mount ~> + user <~ @user-promise.then + @user = user + @update! - @on \mount ~> - user <~ @user-promise.then - @user = user - @update! - - @api \aggregation/users/followers do - user_id: @user.id - limit: 30days - .then (followers) ~> - followers = followers.reverse! - - @api \aggregation/users/following do + @api \aggregation/users/followers do user_id: @user.id limit: 30days - .then (following) ~> - following = following.reverse! + .then (followers) ~> + followers = followers.reverse! - new Chart @refs.canv, do - type: \line - data: - labels: following.map (x, i) ~> if i % 3 == 2 then x.date.day + '日' else '' - datasets: [ - { - label: \フォロー - data: following.map (x) ~> x.count - line-tension: 0 - border-width: 2 - fill: true - background-color: 'rgba(127, 221, 64, 0.2)' - point-background-color: \#fff - point-radius: 4 - point-border-width: 2 - border-color: \#7fdd40 - }, - { - label: \フォロワー - data: followers.map (x) ~> x.count - line-tension: 0 - border-width: 2 - fill: true - background-color: 'rgba(255, 99, 132, 0.2)' - point-background-color: \#fff - point-radius: 4 - point-border-width: 2 - border-color: \#FF6384 - } - ] - options: - responsive: false + @api \aggregation/users/following do + user_id: @user.id + limit: 30days + .then (following) ~> + following = following.reverse! + + new Chart @refs.canv, do + type: \line + data: + labels: following.map (x, i) ~> if i % 3 == 2 then x.date.day + '日' else '' + datasets: [ + { + label: \フォロー + data: following.map (x) ~> x.count + line-tension: 0 + border-width: 2 + fill: true + background-color: 'rgba(127, 221, 64, 0.2)' + point-background-color: \#fff + point-radius: 4 + point-border-width: 2 + border-color: \#7fdd40 + }, + { + label: \フォロワー + data: followers.map (x) ~> x.count + line-tension: 0 + border-width: 2 + fill: true + background-color: 'rgba(255, 99, 132, 0.2)' + point-background-color: \#fff + point-radius: 4 + point-border-width: 2 + border-color: \#FF6384 + } + ] + options: + responsive: false + </script> +</mk-user-friends-graph> diff --git a/src/web/app/desktop/tags/user-graphs.tag b/src/web/app/desktop/tags/user-graphs.tag index f7f0fcd5e0..28643cd90b 100644 --- a/src/web/app/desktop/tags/user-graphs.tag +++ b/src/web/app/desktop/tags/user-graphs.tag @@ -1,36 +1,40 @@ -mk-user-graphs - section - h1 投稿 - mk-user-posts-graph(user={ opts.user }) +<mk-user-graphs> + <section> + <h1>投稿</h1> + <mk-user-posts-graph user="{ opts.user }"></mk-user-posts-graph> + </section> + <section> + <h1>フォロー/フォロワー</h1> + <mk-user-friends-graph user="{ opts.user }"></mk-user-friends-graph> + </section> + <section> + <h1>いいね</h1> + <mk-user-likes-graph user="{ opts.user }"></mk-user-likes-graph> + </section> + <style type="stylus"> + :scope + display block - section - h1 フォロー/フォロワー - mk-user-friends-graph(user={ opts.user }) + > section + margin 16px 0 + background #fff + border solid 1px rgba(0, 0, 0, 0.1) + border-radius 4px - section - h1 いいね - mk-user-likes-graph(user={ opts.user }) + > h1 + margin 0 0 8px 0 + padding 0 16px + line-height 40px + font-size 1em + color #666 + border-bottom solid 1px #eee -style. - display block + > *:not(h1) + margin 0 auto 16px auto - > section - margin 16px 0 - background #fff - border solid 1px rgba(0, 0, 0, 0.1) - border-radius 4px - - > h1 - margin 0 0 8px 0 - padding 0 16px - line-height 40px - font-size 1em - color #666 - border-bottom solid 1px #eee - - > *:not(h1) - margin 0 auto 16px auto - -script. - @on \mount ~> - @trigger \loaded + </style> + <script> + @on \mount ~> + @trigger \loaded + </script> +</mk-user-graphs> diff --git a/src/web/app/desktop/tags/user-header.tag b/src/web/app/desktop/tags/user-header.tag index 5abd79ff1c..7b4ebfb847 100644 --- a/src/web/app/desktop/tags/user-header.tag +++ b/src/web/app/desktop/tags/user-header.tag @@ -1,143 +1,142 @@ -mk-user-header(data-is-dark-background={ user.banner_url != null }) - div.banner@banner(style={ user.banner_url ? 'background-image: url(' + user.banner_url + '?thumbnail&size=1024)' : '' }, onclick={ on-update-banner }) - img.avatar(src={ user.avatar_url + '?thumbnail&size=150' }, alt='avatar') - div.title - p.name(href={ CONFIG.url + '/' + user.username }) { user.name } - p.username @{ user.username } - p.location(if={ user.location }) - i.fa.fa-map-marker - | { user.location } - footer - a(href={ '/' + user.username }) 投稿 - a(href={ '/' + user.username + '/media' }) メディア - a(href={ '/' + user.username + '/graphs' }) グラフ - button(onclick={ NotImplementedException }): i.fa.fa-ellipsis-h +<mk-user-header data-is-dark-background="{ user.banner_url != null }"> + <div class="banner" ref="banner" style="{ user.banner_url ? 'background-image: url(' + user.banner_url + '?thumbnail&size=1024)' : '' }" onclick="{ onUpdateBanner }"></div><img class="avatar" src="{ user.avatar_url + '?thumbnail&size=150' }" alt="avatar"/> + <div class="title"> + <p class="name" href="{ CONFIG.url + '/' + user.username }">{ user.name }</p> + <p class="username">@{ user.username }</p> + <p class="location" if="{ user.location }"><i class="fa fa-map-marker"></i>{ user.location }</p> + </div> + <footer><a href="{ '/' + user.username }">投稿</a><a href="{ '/' + user.username + '/media' }">メディア</a><a href="{ '/' + user.username + '/graphs' }">グラフ</a> + <button onclick="{ NotImplementedException }"><i class="fa fa-ellipsis-h"></i></button> + </footer> + <style type="stylus"> + :scope + $footer-height = 58px -style. - $footer-height = 58px - - display block - background #fff - - &[data-is-dark-background] - > .banner - background-color #383838 - - > .title - color #fff - background linear-gradient(transparent, rgba(0, 0, 0, 0.7)) - - > .name - text-shadow 0 0 8px #000 - - > .banner - height 280px - background-color #f5f5f5 - background-size cover - background-position center - - > .avatar - display block - position absolute - bottom 16px - left 16px - z-index 2 - width 150px - height 150px - margin 0 - border solid 3px #fff - border-radius 8px - box-shadow 1px 1px 3px rgba(0, 0, 0, 0.2) - - > .title - position absolute - bottom $footer-height - left 0 - width 100% - padding 0 0 8px 195px - color #656565 - font-family '游ゴシック', 'YuGothic', 'ヒラギノ角ゴ ProN W3', 'Hiragino Kaku Gothic ProN', 'Meiryo', 'メイリオ', sans-serif - - > .name display block - margin 0 - line-height 40px - font-weight bold - font-size 2em + background #fff - > .username - > .location - display inline-block - margin 0 16px 0 0 - line-height 20px - opacity 0.8 + &[data-is-dark-background] + > .banner + background-color #383838 - > i - margin-right 4px + > .title + color #fff + background linear-gradient(transparent, rgba(0, 0, 0, 0.7)) - > footer - z-index 1 - height $footer-height - padding-left 195px - background #fff + > .name + text-shadow 0 0 8px #000 - > a - display inline-block - margin 0 - width 100px - line-height $footer-height - color #555 + > .banner + height 280px + background-color #f5f5f5 + background-size cover + background-position center - > button - display block - position absolute - top 0 - right 0 - margin 8px - padding 0 - width $footer-height - 16px - line-height $footer-height - 16px - 2px - font-size 1.2em - color #777 - border solid 1px #eee - border-radius 4px + > .avatar + display block + position absolute + bottom 16px + left 16px + z-index 2 + width 150px + height 150px + margin 0 + border solid 3px #fff + border-radius 8px + box-shadow 1px 1px 3px rgba(0, 0, 0, 0.2) - &:hover - color #555 - border solid 1px #ddd + > .title + position absolute + bottom $footer-height + left 0 + width 100% + padding 0 0 8px 195px + color #656565 + font-family '游ゴシック', 'YuGothic', 'ヒラギノ角ゴ ProN W3', 'Hiragino Kaku Gothic ProN', 'Meiryo', 'メイリオ', sans-serif -script. - @mixin \i - @mixin \update-banner - @mixin \NotImplementedException + > .name + display block + margin 0 + line-height 40px + font-weight bold + font-size 2em - @user = @opts.user + > .username + > .location + display inline-block + margin 0 16px 0 0 + line-height 20px + opacity 0.8 - @on \mount ~> - window.add-event-listener \load @scroll - window.add-event-listener \scroll @scroll - window.add-event-listener \resize @scroll + > i + margin-right 4px - @on \unmount ~> - window.remove-event-listener \load @scroll - window.remove-event-listener \scroll @scroll - window.remove-event-listener \resize @scroll + > footer + z-index 1 + height $footer-height + padding-left 195px + background #fff - @scroll = ~> - top = window.scroll-y - height = 280px + > a + display inline-block + margin 0 + width 100px + line-height $footer-height + color #555 - pos = 50 - ((top / height) * 50) - @refs.banner.style.background-position = 'center ' + pos + '%' + > button + display block + position absolute + top 0 + right 0 + margin 8px + padding 0 + width $footer-height - 16px + line-height $footer-height - 16px - 2px + font-size 1.2em + color #777 + border solid 1px #eee + border-radius 4px - blur = top / 32 - if blur <= 10 - @refs.banner.style.filter = 'blur(' + blur + 'px)' + &:hover + color #555 + border solid 1px #ddd - @on-update-banner = ~> - if not @SIGNIN or @I.id != @user.id - return + </style> + <script> + @mixin \i + @mixin \update-banner + @mixin \NotImplementedException - @update-banner @I, (i) ~> - @user.banner_url = i.banner_url - @update! + @user = @opts.user + + @on \mount ~> + window.add-event-listener \load @scroll + window.add-event-listener \scroll @scroll + window.add-event-listener \resize @scroll + + @on \unmount ~> + window.remove-event-listener \load @scroll + window.remove-event-listener \scroll @scroll + window.remove-event-listener \resize @scroll + + @scroll = ~> + top = window.scroll-y + height = 280px + + pos = 50 - ((top / height) * 50) + @refs.banner.style.background-position = 'center ' + pos + '%' + + blur = top / 32 + if blur <= 10 + @refs.banner.style.filter = 'blur(' + blur + 'px)' + + @on-update-banner = ~> + if not @SIGNIN or @I.id != @user.id + return + + @update-banner @I, (i) ~> + @user.banner_url = i.banner_url + @update! + </script> +</mk-user-header> diff --git a/src/web/app/desktop/tags/user-home.tag b/src/web/app/desktop/tags/user-home.tag index 4bf0260ff6..602ce1b9c9 100644 --- a/src/web/app/desktop/tags/user-home.tag +++ b/src/web/app/desktop/tags/user-home.tag @@ -1,40 +1,45 @@ -mk-user-home - div.side - mk-user-profile(user={ user }) - mk-user-photos(user={ user }) - main - mk-user-timeline@tl(user={ user }) +<mk-user-home> + <div class="side"> + <mk-user-profile user="{ user }"></mk-user-profile> + <mk-user-photos user="{ user }"></mk-user-photos> + </div> + <main> + <mk-user-timeline ref="tl" user="{ user }"></mk-user-timeline> + </main> + <style type="stylus"> + :scope + display flex + justify-content center -style. - display flex - justify-content center + > * + > * + display block + //border solid 1px #eaeaea + border solid 1px rgba(0, 0, 0, 0.075) + border-radius 6px + overflow hidden - > * - > * - 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 - &:not(:last-child) - margin-bottom 16px + > main + flex 1 1 560px + max-width 560px + margin 0 + padding 16px 0 16px 16px - > main - flex 1 1 560px - max-width 560px - margin 0 - padding 16px 0 16px 16px + > .side + flex 1 1 270px + max-width 270px + margin 0 + padding 16px 0 16px 0 - > .side - flex 1 1 270px - max-width 270px - margin 0 - padding 16px 0 16px 0 + </style> + <script> + @user = @opts.user -script. - @user = @opts.user - - @on \mount ~> - @refs.tl.on \loaded ~> - @trigger \loaded + @on \mount ~> + @refs.tl.on \loaded ~> + @trigger \loaded + </script> +</mk-user-home> diff --git a/src/web/app/desktop/tags/user-likes-graph.tag b/src/web/app/desktop/tags/user-likes-graph.tag index e9d1428713..1c2759a3a1 100644 --- a/src/web/app/desktop/tags/user-likes-graph.tag +++ b/src/web/app/desktop/tags/user-likes-graph.tag @@ -1,39 +1,42 @@ -mk-user-likes-graph - canvas@canv(width='750', height='250') +<mk-user-likes-graph> + <canvas ref="canv" width="750" height="250"></canvas> + <style type="stylus"> + :scope + display block + width 750px + height 250px -style. - display block - width 750px - height 250px + </style> + <script> + @mixin \api + @mixin \is-promise -script. - @mixin \api - @mixin \is-promise + @user = null + @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user - @user = null - @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user + @on \mount ~> + user <~ @user-promise.then + @user = user + @update! - @on \mount ~> - user <~ @user-promise.then - @user = user - @update! + @api \aggregation/users/like do + user_id: @user.id + limit: 30days + .then (likes) ~> + likes = likes.reverse! - @api \aggregation/users/like do - user_id: @user.id - limit: 30days - .then (likes) ~> - likes = likes.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: \いいねした数 - data: likes.map (x) ~> x.count - background-color: \#F7796C - } - ] - options: - responsive: false + new Chart @refs.canv, do + type: \bar + data: + labels: likes.map (x, i) ~> if i % 3 == 2 then x.date.day + '日' else '' + datasets: [ + { + label: \いいねした数 + data: likes.map (x) ~> x.count + background-color: \#F7796C + } + ] + options: + responsive: false + </script> +</mk-user-likes-graph> diff --git a/src/web/app/desktop/tags/user-photos.tag b/src/web/app/desktop/tags/user-photos.tag index 61a840ee61..eb79113e41 100644 --- a/src/web/app/desktop/tags/user-photos.tag +++ b/src/web/app/desktop/tags/user-photos.tag @@ -1,85 +1,86 @@ -mk-user-photos - 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-user-photos> + <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 && images.length > 0 }"> + <virtual each="{ image in images }"> + <div class="img" style="{ 'background-image: url(' + image.url + '?thumbnail&size=256)' }"></div> + </virtual> + </div> + <p class="empty" if="{ !initializing && 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 \is-promise -script. - @mixin \api - @mixin \is-promise + @images = [] + @initializing = true - @images = [] - @initializing = true + @user = null + @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user - @user = null - @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user - - @on \mount ~> - @user-promise.then (user) ~> - @user = user - @update! - - @api \users/posts do - user_id: @user.id - with_media: true - limit: 9posts - .then (posts) ~> - @initializing = false - posts.for-each (post) ~> - post.media.for-each (image) ~> - if @images.length < 9 - @images.push image + @on \mount ~> + @user-promise.then (user) ~> + @user = user @update! + + @api \users/posts do + user_id: @user.id + with_media: true + limit: 9posts + .then (posts) ~> + @initializing = false + posts.for-each (post) ~> + post.media.for-each (image) ~> + if @images.length < 9 + @images.push image + @update! + </script> +</mk-user-photos> diff --git a/src/web/app/desktop/tags/user-posts-graph.tag b/src/web/app/desktop/tags/user-posts-graph.tag index 75f4ac4a67..61070c3818 100644 --- a/src/web/app/desktop/tags/user-posts-graph.tag +++ b/src/web/app/desktop/tags/user-posts-graph.tag @@ -1,68 +1,71 @@ -mk-user-posts-graph - canvas@canv(width='750', height='250') +<mk-user-posts-graph> + <canvas ref="canv" width="750" height="250"></canvas> + <style type="stylus"> + :scope + display block + width 750px + height 250px -style. - display block - width 750px - height 250px + </style> + <script> + @mixin \api + @mixin \is-promise -script. - @mixin \api - @mixin \is-promise + @user = null + @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user - @user = null - @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user + @on \mount ~> + user <~ @user-promise.then + @user = user + @update! - @on \mount ~> - user <~ @user-promise.then - @user = user - @update! - - @api \aggregation/users/post do - user_id: @user.id - limit: 30days - .then (data) ~> - data = data.reverse! - new Chart @refs.canv, do - type: \line - data: - labels: data.map (x, i) ~> if i % 3 == 2 then x.date.day + '日' else '' - datasets: [ - { - label: \投稿 - data: data.map (x) ~> x.posts - line-tension: 0 - point-radius: 0 - background-color: \#555 - border-color: \transparent - }, - { - label: \Repost - data: data.map (x) ~> x.reposts - line-tension: 0 - point-radius: 0 - background-color: \#a2d61e - border-color: \transparent - }, - { - label: \返信 - data: data.map (x) ~> x.replies - line-tension: 0 - point-radius: 0 - background-color: \#F7796C - border-color: \transparent - } - ] - options: - responsive: false - scales: - x-axes: [ + @api \aggregation/users/post do + user_id: @user.id + limit: 30days + .then (data) ~> + data = data.reverse! + new Chart @refs.canv, do + type: \line + data: + labels: data.map (x, i) ~> if i % 3 == 2 then x.date.day + '日' else '' + datasets: [ { - stacked: true - } - ] - y-axes: [ - { - stacked: true + label: \投稿 + data: data.map (x) ~> x.posts + line-tension: 0 + point-radius: 0 + background-color: \#555 + border-color: \transparent + }, + { + label: \Repost + data: data.map (x) ~> x.reposts + line-tension: 0 + point-radius: 0 + background-color: \#a2d61e + border-color: \transparent + }, + { + label: \返信 + data: data.map (x) ~> x.replies + line-tension: 0 + point-radius: 0 + background-color: \#F7796C + border-color: \transparent } ] + options: + responsive: false + scales: + x-axes: [ + { + stacked: true + } + ] + y-axes: [ + { + stacked: true + } + ] + </script> +</mk-user-posts-graph> diff --git a/src/web/app/desktop/tags/user-preview.tag b/src/web/app/desktop/tags/user-preview.tag index f299e6236e..ed1d868781 100644 --- a/src/web/app/desktop/tags/user-preview.tag +++ b/src/web/app/desktop/tags/user-preview.tag @@ -1,143 +1,148 @@ -mk-user-preview - virtual(if={ user != null }) - div.banner(style={ user.banner_url ? 'background-image: url(' + user.banner_url + '?thumbnail&size=512)' : '' }) - a.avatar(href={ CONFIG.url + '/' + user.username }, target='_blank'): img(src={ user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.title - p.name { user.name } - p.username @{ user.username } - div.bio { user.bio } - div.status - div - p 投稿 - a { user.posts_count } - div - p フォロー - a { user.following_count } - div - p フォロワー - a { user.followers_count } - mk-follow-button(if={ SIGNIN && user.id != I.id }, user={ user-promise }) - -style. - display block - position absolute - z-index 2048 - width 250px - background #fff - background-clip content-box - border solid 1px rgba(0, 0, 0, 0.1) - border-radius 4px - overflow hidden - - // https://github.com/riot/riot/issues/2081 - > virtual - display block - position relative - - > .banner - height 84px - background-color #f5f5f5 - background-size cover - background-position center - - > .avatar +<mk-user-preview> + <virtual if="{ user != null }"> + <div class="banner" style="{ user.banner_url ? 'background-image: url(' + user.banner_url + '?thumbnail&size=512)' : '' }"></div><a class="avatar" href="{ CONFIG.url + '/' + user.username }" target="_blank"><img src="{ user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/></a> + <div class="title"> + <p class="name">{ user.name }</p> + <p class="username">@{ user.username }</p> + </div> + <div class="bio">{ user.bio }</div> + <div class="status"> + <div> + <p>投稿</p><a>{ user.posts_count }</a> + </div> + <div> + <p>フォロー</p><a>{ user.following_count }</a> + </div> + <div> + <p>フォロワー</p><a>{ user.followers_count }</a> + </div> + </div> + <mk-follow-button if="{ SIGNIN && user.id != I.id }" user="{ userPromise }"></mk-follow-button> + </virtual> + <style type="stylus"> + :scope display block position absolute - top 62px - left 13px + z-index 2048 + width 250px + background #fff + background-clip content-box + border solid 1px rgba(0, 0, 0, 0.1) + border-radius 4px + overflow hidden - > img + // https://github.com/riot/riot/issues/2081 + > virtual display block - width 58px - height 58px - margin 0 - border solid 3px #fff - border-radius 8px + position relative - > .title - display block - padding 8px 0 8px 85px + > .banner + height 84px + background-color #f5f5f5 + background-size cover + background-position center - > .name - display block - margin 0 - font-weight bold - line-height 16px - color #656565 + > .avatar + display block + position absolute + top 62px + left 13px - > .username - display block - margin 0 - line-height 16px - font-size 0.8em - color #999 + > img + display block + width 58px + height 58px + margin 0 + border solid 3px #fff + border-radius 8px - > .bio - padding 0 16px - font-size 0.7em - color #555 + > .title + display block + padding 8px 0 8px 85px - > .status - padding 8px 16px + > .name + display block + margin 0 + font-weight bold + line-height 16px + color #656565 - > div - display inline-block - width 33% + > .username + display block + margin 0 + line-height 16px + font-size 0.8em + color #999 - > p - margin 0 + > .bio + padding 0 16px font-size 0.7em - color #aaa + color #555 - > a - font-size 1em - color $theme-color + > .status + padding 8px 16px - > mk-follow-button - position absolute - top 92px - right 8px + > div + display inline-block + width 33% -script. - @mixin \i - @mixin \api + > p + margin 0 + font-size 0.7em + color #aaa - @u = @opts.user - @user = null - @user-promise = - if typeof @u == \string - new Promise (resolve, reject) ~> - @api \users/show do - user_id: if @u.0 == \@ then undefined else @u - username: if @u.0 == \@ then @u.substr 1 else undefined - .then (user) ~> - resolve user - else - Promise.resolve @u + > a + font-size 1em + color $theme-color - @on \mount ~> - @user-promise.then (user) ~> - @user = user - @update! + > mk-follow-button + position absolute + top 92px + right 8px - Velocity @root, { - opacity: 0 - 'margin-top': \-8px - } 0ms - Velocity @root, { - opacity: 1 - 'margin-top': 0 - } { - duration: 200ms - easing: \ease-out - } + </style> + <script> + @mixin \i + @mixin \api - @close = ~> - Velocity @root, { - opacity: 0 - 'margin-top': \-8px - } { - duration: 200ms - easing: \ease-out - complete: ~> @unmount! - } + @u = @opts.user + @user = null + @user-promise = + if typeof @u == \string + new Promise (resolve, reject) ~> + @api \users/show do + user_id: if @u.0 == \@ then undefined else @u + username: if @u.0 == \@ then @u.substr 1 else undefined + .then (user) ~> + resolve user + else + Promise.resolve @u + + @on \mount ~> + @user-promise.then (user) ~> + @user = user + @update! + + Velocity @root, { + opacity: 0 + 'margin-top': \-8px + } 0ms + Velocity @root, { + opacity: 1 + 'margin-top': 0 + } { + duration: 200ms + easing: \ease-out + } + + @close = ~> + Velocity @root, { + opacity: 0 + 'margin-top': \-8px + } { + duration: 200ms + easing: \ease-out + complete: ~> @unmount! + } + </script> +</mk-user-preview> diff --git a/src/web/app/desktop/tags/user-profile.tag b/src/web/app/desktop/tags/user-profile.tag index adb685845c..1079282ed3 100644 --- a/src/web/app/desktop/tags/user-profile.tag +++ b/src/web/app/desktop/tags/user-profile.tag @@ -1,86 +1,83 @@ -mk-user-profile - div.friend-form(if={ SIGNIN && I.id != user.id }) - mk-big-follow-button(user={ user }) - p.followed(if={ user.is_followed }) フォローされています - div.bio(if={ user.bio != '' }) { user.bio } - div.birthday(if={ user.birthday }): p - i.fa.fa-birthday-cake - | { user.birthday.replace('-', '年').replace('-', '月') + '日' } - div.friends - p.following - i.fa.fa-angle-right - a(onclick={ show-following }) { user.following_count } - | 人を - b フォロー - p.followers - i.fa.fa-angle-right - a(onclick={ show-followers }) { user.followers_count } - | 人の - b フォロワー +<mk-user-profile> + <div class="friend-form" if="{ SIGNIN && I.id != user.id }"> + <mk-big-follow-button user="{ user }"></mk-big-follow-button> + <p class="followed" if="{ user.is_followed }">フォローされています</p> + </div> + <div class="bio" if="{ user.bio != '' }">{ user.bio }</div> + <div class="birthday" if="{ user.birthday }"> + <p><i class="fa fa-birthday-cake"></i>{ user.birthday.replace('-', '年').replace('-', '月') + '日' }</p> + </div> + <div class="friends"> + <p class="following"><i class="fa fa-angle-right"></i><a onclick="{ showFollowing }">{ user.following_count }</a>人を<b>フォロー</b></p> + <p class="followers"><i class="fa fa-angle-right"></i><a onclick="{ showFollowers }">{ user.followers_count }</a>人の<b>フォロワー</b></p> + </div> + <style type="stylus"> + :scope + display block + background #fff -style. - display block - background #fff + > *:first-child + border-top none !important - > *:first-child - border-top none !important + > .friend-form + padding 16px + border-top solid 1px #eee - > .friend-form - padding 16px - border-top solid 1px #eee + > mk-big-follow-button + width 100% - > mk-big-follow-button - width 100% + > .followed + margin 12px 0 0 0 + padding 0 + text-align center + line-height 24px + font-size 0.8em + color #71afc7 + background #eefaff + border-radius 4px - > .followed - margin 12px 0 0 0 - padding 0 - text-align center - line-height 24px - font-size 0.8em - color #71afc7 - background #eefaff - border-radius 4px + > .bio + padding 16px + color #555 + border-top solid 1px #eee - > .bio - padding 16px - color #555 - border-top solid 1px #eee + > .birthday + padding 16px + color #555 + border-top solid 1px #eee - > .birthday - padding 16px - color #555 - border-top solid 1px #eee + > p + margin 0 - > p - margin 0 + > i + margin-right 8px - > i - margin-right 8px + > .friends + padding 16px + color #555 + border-top solid 1px #eee - > .friends - padding 16px - color #555 - border-top solid 1px #eee + > p + margin 8px 0 - > p - margin 8px 0 + > i + margin-left 8px + margin-right 8px - > i - margin-left 8px - margin-right 8px + </style> + <script> + @mixin \i -script. - @mixin \i + @user = @opts.user - @user = @opts.user + @show-following = ~> + window = document.body.append-child document.create-element \mk-user-following-window + riot.mount window, do + user: @user - @show-following = ~> - window = document.body.append-child document.create-element \mk-user-following-window - riot.mount window, do - user: @user - - @show-followers = ~> - window = document.body.append-child document.create-element \mk-user-followers-window - riot.mount window, do - user: @user + @show-followers = ~> + window = document.body.append-child document.create-element \mk-user-followers-window + riot.mount window, do + user: @user + </script> +</mk-user-profile> diff --git a/src/web/app/desktop/tags/user-timeline.tag b/src/web/app/desktop/tags/user-timeline.tag index ced90e2e84..89eb53933a 100644 --- a/src/web/app/desktop/tags/user-timeline.tag +++ b/src/web/app/desktop/tags/user-timeline.tag @@ -1,142 +1,138 @@ -mk-user-timeline - header - span(data-is-active={ mode == 'default' }, onclick={ set-mode.bind(this, 'default') }) 投稿 - span(data-is-active={ mode == 'with-replies' }, onclick={ set-mode.bind(this, 'with-replies') }) 投稿と返信 - 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 - - > 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-user-timeline> + <header><span data-is-active="{ mode == 'default' }" onclick="{ setMode.bind(this, 'default') }">投稿</span><span data-is-active="{ mode == 'with-replies' }" onclick="{ setMode.bind(this, 'with-replies') }">投稿と返信</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>このユーザーはまだ何も投稿していないようです。</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 \is-promise - @mixin \get-post-summary + > header + padding 8px 16px + border-bottom solid 1px #eee - @user = null - @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user - @is-loading = true - @is-empty = false - @more-loading = false - @unread-count = 0 - @mode = \default + > span + margin-right 16px + line-height 27px + font-size 18px + color #555 - @on \mount ~> - document.add-event-listener \visibilitychange @window-on-visibilitychange, false - document.add-event-listener \keydown @on-document-keydown - window.add-event-listener \scroll @on-scroll + &:not([data-is-active]) + color $theme-color + cursor pointer - @user-promise.then (user) ~> - @user = user - @update! + &:hover + text-decoration underline - @fetch ~> - @trigger \loaded + > .loading + padding 64px 0 - @on \unmount ~> - document.remove-event-listener \visibilitychange @window-on-visibilitychange - document.remove-event-listener \keydown @on-document-keydown - window.remove-event-listener \scroll @on-scroll + > .empty + display block + margin 0 auto + padding 32px + max-width 400px + text-align center + color #999 - @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! + > i + display block + margin-bottom 16px + font-size 3em + color #ccc - @fetch = (cb) ~> - @api \users/posts do - user_id: @user.id - with_replies: @mode == \with-replies - .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! + </style> + <script> + @mixin \api + @mixin \is-promise + @mixin \get-post-summary - @more = ~> - if @more-loading or @is-loading or @refs.timeline.posts.length == 0 - return - @more-loading = true - @update! - @api \users/posts do - user_id: @user.id - with_replies: @mode == \with-replies - 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) ~> + @user = null + @user-promise = if @is-promise @opts.user then @opts.user else Promise.resolve @opts.user + @is-loading = true @is-empty = false - @update! - @refs.timeline.add-post post + @more-loading = false + @unread-count = 0 + @mode = \default - if document.hidden - @unread-count++ - document.title = '(' + @unread-count + ') ' + @get-post-summary post + @on \mount ~> + document.add-event-listener \visibilitychange @window-on-visibilitychange, false + document.add-event-listener \keydown @on-document-keydown + window.add-event-listener \scroll @on-scroll - @window-on-visibilitychange = ~> - if !document.hidden - @unread-count = 0 - document.title = 'Misskey' + @user-promise.then (user) ~> + @user = user + @update! - @on-scroll = ~> - current = window.scroll-y + window.inner-height - if current > document.body.offset-height - 16 # 遊び - @more! + @fetch ~> + @trigger \loaded - @set-mode = (mode) ~> - @update do - mode: mode - @fetch! + @on \unmount ~> + document.remove-event-listener \visibilitychange @window-on-visibilitychange + 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 \users/posts do + user_id: @user.id + with_replies: @mode == \with-replies + .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 \users/posts do + user_id: @user.id + with_replies: @mode == \with-replies + 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 + + if document.hidden + @unread-count++ + document.title = '(' + @unread-count + ') ' + @get-post-summary post + + @window-on-visibilitychange = ~> + if !document.hidden + @unread-count = 0 + document.title = 'Misskey' + + @on-scroll = ~> + current = window.scroll-y + window.inner-height + if current > document.body.offset-height - 16 # 遊び + @more! + + @set-mode = (mode) ~> + @update do + mode: mode + @fetch! + </script> +</mk-user-timeline> diff --git a/src/web/app/desktop/tags/user.tag b/src/web/app/desktop/tags/user.tag index 4d022e68c4..777d9caee7 100644 --- a/src/web/app/desktop/tags/user.tag +++ b/src/web/app/desktop/tags/user.tag @@ -1,45 +1,51 @@ -mk-user - div.user(if={ !fetching }) - header - mk-user-header(user={ user }) - div.body - mk-user-home(if={ page == 'home' }, user={ user }) - mk-user-graphs(if={ page == 'graphs' }, user={ user }) +<mk-user> + <div class="user" if="{ !fetching }"> + <header> + <mk-user-header user="{ user }"></mk-user-header> + </header> + <div class="body"> + <mk-user-home if="{ page == 'home' }" user="{ user }"></mk-user-home> + <mk-user-graphs if="{ page == 'graphs' }" user="{ user }"></mk-user-graphs> + </div> + </div> + <style type="stylus"> + :scope + display block + background #fff -style. - display block - background #fff + > .user + > header + max-width 560px + 270px + margin 0 auto + padding 0 16px - > .user - > header - max-width 560px + 270px - margin 0 auto - padding 0 16px + > mk-user-header + border solid 1px rgba(0, 0, 0, 0.075) + border-top none + border-radius 0 0 6px 6px + overflow hidden - > mk-user-header - border solid 1px rgba(0, 0, 0, 0.075) - border-top none - border-radius 0 0 6px 6px - overflow hidden + > .body + max-width 560px + 270px + margin 0 auto + padding 0 16px - > .body - max-width 560px + 270px - margin 0 auto - padding 0 16px + </style> + <script> + @mixin \api -script. - @mixin \api + @username = @opts.user + @page = if @opts.page? then @opts.page else \home + @fetching = true + @user = null - @username = @opts.user - @page = if @opts.page? then @opts.page else \home - @fetching = true - @user = null - - @on \mount ~> - @api \users/show do - username: @username - .then (user) ~> - @fetching = false - @user = user - @update! - @trigger \loaded + @on \mount ~> + @api \users/show do + username: @username + .then (user) ~> + @fetching = false + @user = user + @update! + @trigger \loaded + </script> +</mk-user> diff --git a/src/web/app/desktop/tags/users-list.tag b/src/web/app/desktop/tags/users-list.tag index 9ae96eed9f..e2b0ef1332 100644 --- a/src/web/app/desktop/tags/users-list.tag +++ b/src/web/app/desktop/tags/users-list.tag @@ -1,139 +1,134 @@ -mk-users-list - nav: div - span(data-is-active={ mode == 'all' }, onclick={ set-mode.bind(this, 'all') }) - | すべて - span { opts.count } - // ↓ https://github.com/riot/riot/issues/2080 - span(if={ SIGNIN && opts.you-know-count != '' }, data-is-active={ mode == 'iknow' }, onclick={ set-mode.bind(this, 'iknow') }) - | 知り合い - span { opts.you-know-count } +<mk-users-list> + <nav> + <div><span data-is-active="{ mode == 'all' }" onclick="{ setMode.bind(this, 'all') }">すべて<span>{ opts.count }</span></span> + <!-- ↓ https://github.com/riot/riot/issues/2080--><span if="{ SIGNIN && opts.youKnowCount != '' }" data-is-active="{ mode == 'iknow' }" onclick="{ setMode.bind(this, 'iknow') }">知り合い<span>{ opts.youKnowCount }</span></span> + </div> + </nav> + <div class="users" if="{ !fetching && users.length != 0 }"> + <div each="{ users }"> + <mk-list-user user="{ this }"></mk-list-user> + </div> + </div> + <button class="more" if="{ !fetching && next != null }" onclick="{ more }" disabled="{ moreFetching }"><span if="{ !moreFetching }">もっと</span><span if="{ moreFetching }">読み込み中 + <mk-ellipsis></mk-ellipsis></span></button> + <p class="no" if="{ !fetching && users.length == 0 }">{ opts.noUsers }</p> + <p class="fetching" if="{ fetching }"><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます + <mk-ellipsis></mk-ellipsis> + </p> + <style type="stylus"> + :scope + display block + height 100% + background #fff - div.users(if={ !fetching && users.length != 0 }) - div(each={ users }): mk-list-user(user={ this }) + > nav + z-index 1 + box-shadow 0 1px 0 rgba(#000, 0.1) - button.more(if={ !fetching && next != null }, onclick={ more }, disabled={ more-fetching }) - span(if={ !more-fetching }) もっと - span(if={ more-fetching }) - | 読み込み中 - mk-ellipsis + > div + display flex + justify-content center + margin 0 auto + max-width 600px - p.no(if={ !fetching && users.length == 0 }) - | { opts.no-users } - p.fetching(if={ fetching }) - i.fa.fa-spinner.fa-pulse.fa-fw - | 読み込んでいます - mk-ellipsis + > span + display block + flex 1 1 + text-align center + line-height 52px + font-size 14px + color #657786 + border-bottom solid 2px transparent + cursor pointer -style. - display block - height 100% - background #fff + * + pointer-events none - > nav - z-index 1 - box-shadow 0 1px 0 rgba(#000, 0.1) + &[data-is-active] + font-weight bold + color $theme-color + border-color $theme-color + cursor default - > div - display flex - justify-content center - margin 0 auto - max-width 600px + > span + display inline-block + margin-left 4px + padding 2px 5px + font-size 12px + line-height 1 + color #888 + background #eee + border-radius 20px - > span - display block - flex 1 1 + > .users + height calc(100% - 54px) + overflow auto + + > * + border-bottom solid 1px rgba(0, 0, 0, 0.05) + + > * + max-width 600px + margin 0 auto + + > .no + margin 0 + padding 16px text-align center - line-height 52px - font-size 14px - color #657786 - border-bottom solid 2px transparent - cursor pointer + color #aaa - * - pointer-events none + > .fetching + margin 0 + padding 16px + text-align center + color #aaa - &[data-is-active] - font-weight bold - color $theme-color - border-color $theme-color - cursor default + > i + margin-right 4px - > span - display inline-block - margin-left 4px - padding 2px 5px - font-size 12px - line-height 1 - color #888 - background #eee - border-radius 20px + </style> + <script> + @mixin \i - > .users - height calc(100% - 54px) - overflow auto + @limit = 30users + @mode = \all - > * - border-bottom solid 1px rgba(0, 0, 0, 0.05) - - > * - max-width 600px - margin 0 auto - - > .no - margin 0 - padding 16px - text-align center - color #aaa - - > .fetching - margin 0 - padding 16px - text-align center - color #aaa - - > i - margin-right 4px - -script. - @mixin \i - - @limit = 30users - @mode = \all - - @fetching = true - @more-fetching = false - - @on \mount ~> - @fetch ~> - @trigger \loaded - - @fetch = (cb) ~> @fetching = true - @update! - obj <~ @opts.fetch do - @mode == \iknow - @limit - null - @users = obj.users - @next = obj.next - @fetching = false - @update! - if cb? then cb! - - @more = ~> - @more-fetching = true - @update! - obj <~ @opts.fetch do - @mode == \iknow - @limit - @cursor - @users = @users.concat obj.users - @next = obj.next @more-fetching = false - @update! - @set-mode = (mode) ~> - @update do - mode: mode + @on \mount ~> + @fetch ~> + @trigger \loaded - @fetch! + @fetch = (cb) ~> + @fetching = true + @update! + obj <~ @opts.fetch do + @mode == \iknow + @limit + null + @users = obj.users + @next = obj.next + @fetching = false + @update! + if cb? then cb! + + @more = ~> + @more-fetching = true + @update! + obj <~ @opts.fetch do + @mode == \iknow + @limit + @cursor + @users = @users.concat obj.users + @next = obj.next + @more-fetching = false + @update! + + @set-mode = (mode) ~> + @update do + mode: mode + + @fetch! + </script> +</mk-users-list> diff --git a/src/web/app/desktop/tags/window.tag b/src/web/app/desktop/tags/window.tag index 9732a6c552..750df64df0 100644 --- a/src/web/app/desktop/tags/window.tag +++ b/src/web/app/desktop/tags/window.tag @@ -1,515 +1,519 @@ -mk-window(data-flexible={ is-flexible }, data-colored={ opts.colored }, ondragover={ ondragover }) - div.bg@bg(show={ is-modal }, onclick={ bg-click }) - div.main@main(tabindex='-1', data-is-modal={ is-modal }, onmousedown={ on-body-mousedown }, onkeydown={ on-keydown }) - div.body - header@header(onmousedown={ on-header-mousedown }) - h1(data-yield='header') - | <yield from="header"/> - button.close(if={ can-close }, onmousedown={ repel-move }, onclick={ close }, title='閉じる'): i.fa.fa-times - div.content(data-yield='content') - | <yield from="content"/> - div.handle.top(if={ can-resize }, onmousedown={ on-top-handle-mousedown }) - div.handle.right(if={ can-resize }, onmousedown={ on-right-handle-mousedown }) - div.handle.bottom(if={ can-resize }, onmousedown={ on-bottom-handle-mousedown }) - div.handle.left(if={ can-resize }, onmousedown={ on-left-handle-mousedown }) - div.handle.top-left(if={ can-resize }, onmousedown={ on-top-left-handle-mousedown }) - div.handle.top-right(if={ can-resize }, onmousedown={ on-top-right-handle-mousedown }) - div.handle.bottom-right(if={ can-resize }, onmousedown={ on-bottom-right-handle-mousedown }) - div.handle.bottom-left(if={ can-resize }, onmousedown={ on-bottom-left-handle-mousedown }) +<mk-window data-flexible="{ isFlexible }" data-colored="{ opts.colored }" ondragover="{ ondragover }"> + <div class="bg" ref="bg" show="{ isModal }" onclick="{ bgClick }"></div> + <div class="main" ref="main" tabindex="-1" data-is-modal="{ isModal }" onmousedown="{ onBodyMousedown }" onkeydown="{ onKeydown }"> + <div class="body"> + <header ref="header" onmousedown="{ onHeaderMousedown }"> + <h1 data-yield="header"><yield from="header"/></h1> + <button class="close" if="{ canClose }" onmousedown="{ repelMove }" onclick="{ close }" title="閉じる"><i class="fa fa-times"></i></button> + </header> + <div class="content" data-yield="content"><yield from="content"/></div> + </div> + <div class="handle top" if="{ canResize }" onmousedown="{ onTopHandleMousedown }"></div> + <div class="handle right" if="{ canResize }" onmousedown="{ onRightHandleMousedown }"></div> + <div class="handle bottom" if="{ canResize }" onmousedown="{ onBottomHandleMousedown }"></div> + <div class="handle left" if="{ canResize }" onmousedown="{ onLeftHandleMousedown }"></div> + <div class="handle top-left" if="{ canResize }" onmousedown="{ onTopLeftHandleMousedown }"></div> + <div class="handle top-right" if="{ canResize }" onmousedown="{ onTopRightHandleMousedown }"></div> + <div class="handle bottom-right" if="{ canResize }" onmousedown="{ onBottomRightHandleMousedown }"></div> + <div class="handle bottom-left" if="{ canResize }" onmousedown="{ onBottomLeftHandleMousedown }"></div> + </div> + <style type="stylus"> + :scope + display block -style. - display block - - > .bg - display block - position fixed - z-index 2048 - 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 2048 - top 15% - left 0 - margin 0 - opacity 0 - pointer-events none - - &:focus - &:not([data-is-modal]) - > .body - box-shadow 0 0 0px 1px rgba($theme-color, 0.5), 0 2px 6px 0 rgba(0, 0, 0, 0.2) - - > .handle - $size = 8px - - position absolute - - &.top - top -($size) + > .bg + display block + position fixed + z-index 2048 + top 0 left 0 width 100% - height $size - cursor ns-resize - - &.right - top 0 - right -($size) - width $size height 100% - cursor ew-resize + background rgba(0, 0, 0, 0.7) + opacity 0 + pointer-events none - &.bottom - bottom -($size) + > .main + display block + position fixed + z-index 2048 + top 15% left 0 - width 100% - height $size - cursor ns-resize + margin 0 + opacity 0 + pointer-events none - &.left - top 0 - left -($size) - width $size - height 100% - cursor ew-resize + &:focus + &:not([data-is-modal]) + > .body + box-shadow 0 0 0px 1px rgba($theme-color, 0.5), 0 2px 6px 0 rgba(0, 0, 0, 0.2) - &.top-left - top -($size) - left -($size) - width $size * 2 - height $size * 2 - cursor nwse-resize + > .handle + $size = 8px - &.top-right - top -($size) - right -($size) - width $size * 2 - height $size * 2 - cursor nesw-resize - - &.bottom-right - bottom -($size) - right -($size) - width $size * 2 - height $size * 2 - cursor nwse-resize - - &.bottom-left - bottom -($size) - left -($size) - width $size * 2 - height $size * 2 - cursor nesw-resize - - > .body - height 100% - overflow hidden - background #fff - border-radius 6px - box-shadow 0 2px 6px 0 rgba(0, 0, 0, 0.2) - - > header - z-index 128 - overflow hidden - cursor move - background #fff - border-radius 6px 6px 0 0 - box-shadow 0 1px 0 rgba(#000, 0.1) - - &, * - user-select none - - > h1 - pointer-events none - display block - margin 0 - height 40px - text-align center - font-size 1em - line-height 40px - font-weight normal - color #666 - - > .close - cursor pointer - display block position absolute - top 0 - right 0 - z-index 1 - margin 0 - padding 0 - font-size 1.2em - color rgba(#000, 0.4) - border none - outline none - background transparent - &:hover - color rgba(#000, 0.6) + &.top + top -($size) + left 0 + width 100% + height $size + cursor ns-resize - &:active - color darken(#000, 30%) + &.right + top 0 + right -($size) + width $size + height 100% + cursor ew-resize - > i - padding 0 - width 40px - line-height 40px + &.bottom + bottom -($size) + left 0 + width 100% + height $size + cursor ns-resize - > .content - height 100% + &.left + top 0 + left -($size) + width $size + height 100% + cursor ew-resize - &:not([flexible]) - > .main > .body > .content - height calc(100% - 40px) + &.top-left + top -($size) + left -($size) + width $size * 2 + height $size * 2 + cursor nwse-resize - &[data-colored] + &.top-right + top -($size) + right -($size) + width $size * 2 + height $size * 2 + cursor nesw-resize - > .main > .body + &.bottom-right + bottom -($size) + right -($size) + width $size * 2 + height $size * 2 + cursor nwse-resize - > header - box-shadow 0 1px 0 rgba($theme-color, 0.1) + &.bottom-left + bottom -($size) + left -($size) + width $size * 2 + height $size * 2 + cursor nesw-resize - > h1 - color #d0b4ac + > .body + height 100% + overflow hidden + background #fff + border-radius 6px + box-shadow 0 2px 6px 0 rgba(0, 0, 0, 0.2) - > .close - color rgba($theme-color, 0.4) + > header + z-index 128 + overflow hidden + cursor move + background #fff + border-radius 6px 6px 0 0 + box-shadow 0 1px 0 rgba(#000, 0.1) - &:hover - color rgba($theme-color, 0.6) + &, * + user-select none - &:active - color darken($theme-color, 30%) + > h1 + pointer-events none + display block + margin 0 + height 40px + text-align center + font-size 1em + line-height 40px + font-weight normal + color #666 -script. - @min-height = 40px - @min-width = 200px + > .close + cursor pointer + display block + position absolute + top 0 + right 0 + z-index 1 + margin 0 + padding 0 + font-size 1.2em + color rgba(#000, 0.4) + border none + outline none + background transparent - @is-modal = if @opts.is-modal? then @opts.is-modal else false - @can-close = if @opts.can-close? then @opts.can-close else true - @is-flexible = !@opts.height? - @can-resize = not @is-flexible + &:hover + color rgba(#000, 0.6) - @on \mount ~> - @refs.main.style.width = @opts.width || \530px - @refs.main.style.height = @opts.height || \auto + &:active + color darken(#000, 30%) - @refs.main.style.top = \15% - @refs.main.style.left = (window.inner-width / 2) - (@refs.main.offset-width / 2) + \px + > i + padding 0 + width 40px + line-height 40px - @refs.header.add-event-listener \contextmenu (e) ~> - e.prevent-default! + > .content + height 100% - window.add-event-listener \resize @on-browser-resize + &:not([flexible]) + > .main > .body > .content + height calc(100% - 40px) - @open! + &[data-colored] - @on \unmount ~> - window.remove-event-listener \resize @on-browser-resize + > .main > .body - @on-browser-resize = ~> - position = @refs.main.get-bounding-client-rect! - browser-width = window.inner-width - browser-height = window.inner-height - window-width = @refs.main.offset-width - window-height = @refs.main.offset-height + > header + box-shadow 0 1px 0 rgba($theme-color, 0.1) - if position.left < 0 - @refs.main.style.left = 0 + > h1 + color #d0b4ac - if position.top < 0 - @refs.main.style.top = 0 + > .close + color rgba($theme-color, 0.4) - if position.left + window-width > browser-width - @refs.main.style.left = browser-width - window-width + \px + &:hover + color rgba($theme-color, 0.6) - if position.top + window-height > browser-height - @refs.main.style.top = browser-height - window-height + \px + &:active + color darken($theme-color, 30%) - @open = ~> - @trigger \opening + </style> + <script> + @min-height = 40px + @min-width = 200px - @top! + @is-modal = if @opts.is-modal? then @opts.is-modal else false + @can-close = if @opts.can-close? then @opts.can-close else true + @is-flexible = !@opts.height? + @can-resize = not @is-flexible - if @is-modal - @refs.bg.style.pointer-events = \auto - Velocity @refs.bg, \finish true - Velocity @refs.bg, { + @on \mount ~> + @refs.main.style.width = @opts.width || \530px + @refs.main.style.height = @opts.height || \auto + + @refs.main.style.top = \15% + @refs.main.style.left = (window.inner-width / 2) - (@refs.main.offset-width / 2) + \px + + @refs.header.add-event-listener \contextmenu (e) ~> + e.prevent-default! + + window.add-event-listener \resize @on-browser-resize + + @open! + + @on \unmount ~> + window.remove-event-listener \resize @on-browser-resize + + @on-browser-resize = ~> + position = @refs.main.get-bounding-client-rect! + browser-width = window.inner-width + browser-height = window.inner-height + window-width = @refs.main.offset-width + window-height = @refs.main.offset-height + + if position.left < 0 + @refs.main.style.left = 0 + + if position.top < 0 + @refs.main.style.top = 0 + + if position.left + window-width > browser-width + @refs.main.style.left = browser-width - window-width + \px + + if position.top + window-height > browser-height + @refs.main.style.top = browser-height - window-height + \px + + @open = ~> + @trigger \opening + + @top! + + if @is-modal + @refs.bg.style.pointer-events = \auto + Velocity @refs.bg, \finish true + Velocity @refs.bg, { + opacity: 1 + } { + queue: false + duration: 100ms + easing: \linear + } + + @refs.main.style.pointer-events = \auto + Velocity @refs.main, \finish true + Velocity @refs.main, {scale: 1.1} 0ms + Velocity @refs.main, { opacity: 1 + scale: 1 } { queue: false - duration: 100ms - easing: \linear + duration: 200ms + easing: \ease-out } - @refs.main.style.pointer-events = \auto - Velocity @refs.main, \finish true - Velocity @refs.main, {scale: 1.1} 0ms - Velocity @refs.main, { - opacity: 1 - scale: 1 - } { - queue: false - duration: 200ms - easing: \ease-out - } + #@refs.main.focus! - #@refs.main.focus! + set-timeout ~> + @trigger \opened + , 300ms - set-timeout ~> - @trigger \opened - , 300ms + @close = ~> + @trigger \closing - @close = ~> - @trigger \closing + if @is-modal + @refs.bg.style.pointer-events = \none + Velocity @refs.bg, \finish true + Velocity @refs.bg, { + opacity: 0 + } { + queue: false + duration: 300ms + easing: \linear + } - if @is-modal - @refs.bg.style.pointer-events = \none - Velocity @refs.bg, \finish true - Velocity @refs.bg, { + @refs.main.style.pointer-events = \none + Velocity @refs.main, \finish true + Velocity @refs.main, { opacity: 0 + scale: 0.8 } { queue: false duration: 300ms - easing: \linear + easing: [ 0.5, -0.5, 1, 0.5 ] } - @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 ] - } + set-timeout ~> + @trigger \closed + , 300ms - set-timeout ~> - @trigger \closed - , 300ms + # 最前面へ移動します + @top = ~> + z = 0 - # 最前面へ移動します - @top = ~> - z = 0 + ws = document.query-selector-all \mk-window + ws.for-each (w) !~> + if w == @root then return + m = w.query-selector ':scope > .main' + mz = Number(document.default-view.get-computed-style m, null .z-index) + if mz > z then z := mz - ws = document.query-selector-all \mk-window - ws.for-each (w) !~> - if w == @root then return - m = w.query-selector ':scope > .main' - mz = Number(document.default-view.get-computed-style m, null .z-index) - if mz > z then z := mz + if z > 0 + @refs.main.style.z-index = z + 1 + if @is-modal then @refs.bg.style.z-index = z + 1 - if z > 0 - @refs.main.style.z-index = z + 1 - if @is-modal then @refs.bg.style.z-index = z + 1 + @repel-move = (e) ~> + e.stop-propagation! + return true - @repel-move = (e) ~> - e.stop-propagation! - return true - - @bg-click = ~> - if @can-close - @close! - - @on-body-mousedown = (e) ~> - @top! - true - - # ヘッダー掴み時 - @on-header-mousedown = (e) ~> - e.prevent-default! - - if not contains @refs.main, document.active-element - @refs.main.focus! - - position = @refs.main.get-bounding-client-rect! - - click-x = e.client-x - click-y = e.client-y - move-base-x = click-x - position.left - move-base-y = click-y - position.top - browser-width = window.inner-width - browser-height = window.inner-height - window-width = @refs.main.offset-width - window-height = @refs.main.offset-height - - # 動かした時 - drag-listen (me) ~> - move-left = me.client-x - move-base-x - move-top = me.client-y - move-base-y - - # 上はみ出し - if move-top < 0 - move-top = 0 - - # 左はみ出し - if move-left < 0 - move-left = 0 - - # 下はみ出し - if move-top + window-height > browser-height - move-top = browser-height - window-height - - # 右はみ出し - if move-left + window-width > browser-width - move-left = browser-width - window-width - - @refs.main.style.left = move-left + \px - @refs.main.style.top = move-top + \px - - # 上ハンドル掴み時 - @on-top-handle-mousedown = (e) ~> - e.prevent-default! - - base = e.client-y - height = parse-int((get-computed-style @refs.main, '').height, 10) - top = parse-int((get-computed-style @refs.main, '').top, 10) - - # 動かした時 - drag-listen (me) ~> - move = me.client-y - base - if top + move > 0 - if height + -move > @min-height - @apply-transform-height height + -move - @apply-transform-top top + move - else # 最小の高さより小さくなろうとした時 - @apply-transform-height @min-height - @apply-transform-top top + (height - @min-height) - else # 上のはみ出し時 - @apply-transform-height top + height - @apply-transform-top 0 - - # 右ハンドル掴み時 - @on-right-handle-mousedown = (e) ~> - e.prevent-default! - - base = e.client-x - width = parse-int((get-computed-style @refs.main, '').width, 10) - left = parse-int((get-computed-style @refs.main, '').left, 10) - browser-width = window.inner-width - - # 動かした時 - drag-listen (me) ~> - move = me.client-x - base - if left + width + move < browser-width - if width + move > @min-width - @apply-transform-width width + move - else # 最小の幅より小さくなろうとした時 - @apply-transform-width @min-width - else # 右のはみ出し時 - @apply-transform-width browser-width - left - - # 下ハンドル掴み時 - @on-bottom-handle-mousedown = (e) ~> - e.prevent-default! - - base = e.client-y - height = parse-int((get-computed-style @refs.main, '').height, 10) - top = parse-int((get-computed-style @refs.main, '').top, 10) - browser-height = window.inner-height - - # 動かした時 - drag-listen (me) ~> - move = me.client-y - base - if top + height + move < browser-height - if height + move > @min-height - @apply-transform-height height + move - else # 最小の高さより小さくなろうとした時 - @apply-transform-height @min-height - else # 下のはみ出し時 - @apply-transform-height browser-height - top - - # 左ハンドル掴み時 - @on-left-handle-mousedown = (e) ~> - e.prevent-default! - - base = e.client-x - width = parse-int((get-computed-style @refs.main, '').width, 10) - left = parse-int((get-computed-style @refs.main, '').left, 10) - - # 動かした時 - drag-listen (me) ~> - move = me.client-x - base - if left + move > 0 - if width + -move > @min-width - @apply-transform-width width + -move - @apply-transform-left left + move - else # 最小の幅より小さくなろうとした時 - @apply-transform-width @min-width - @apply-transform-left left + (width - @min-width) - else # 左のはみ出し時 - @apply-transform-width left + width - @apply-transform-left 0 - - # 左上ハンドル掴み時 - @on-top-left-handle-mousedown = (e) ~> - @on-top-handle-mousedown e - @on-left-handle-mousedown e - - # 右上ハンドル掴み時 - @on-top-right-handle-mousedown = (e) ~> - @on-top-handle-mousedown e - @on-right-handle-mousedown e - - # 右下ハンドル掴み時 - @on-bottom-right-handle-mousedown = (e) ~> - @on-bottom-handle-mousedown e - @on-right-handle-mousedown e - - # 左下ハンドル掴み時 - @on-bottom-left-handle-mousedown = (e) ~> - @on-bottom-handle-mousedown e - @on-left-handle-mousedown e - - # 高さを適用 - @apply-transform-height = (height) ~> - @refs.main.style.height = height + \px - - # 幅を適用 - @apply-transform-width = (width) ~> - @refs.main.style.width = width + \px - - # Y座標を適用 - @apply-transform-top = (top) ~> - @refs.main.style.top = top + \px - - # X座標を適用 - @apply-transform-left = (left) ~> - @refs.main.style.left = left + \px - - function drag-listen fn - window.add-event-listener \mousemove fn - window.add-event-listener \mouseleave drag-clear.bind null fn - window.add-event-listener \mouseup drag-clear.bind null fn - - function drag-clear fn - window.remove-event-listener \mousemove fn - window.remove-event-listener \mouseleave drag-clear - window.remove-event-listener \mouseup drag-clear - - @ondragover = (e) ~> - e.data-transfer.drop-effect = \none - - @on-keydown = (e) ~> - if e.which == 27 # Esc + @bg-click = ~> if @can-close - e.prevent-default! - e.stop-propagation! @close! - function contains(parent, child) - node = child.parent-node - while node? - if node == parent - return true - node = node.parent-node - return false + @on-body-mousedown = (e) ~> + @top! + true + + # ヘッダー掴み時 + @on-header-mousedown = (e) ~> + e.prevent-default! + + if not contains @refs.main, document.active-element + @refs.main.focus! + + position = @refs.main.get-bounding-client-rect! + + click-x = e.client-x + click-y = e.client-y + move-base-x = click-x - position.left + move-base-y = click-y - position.top + browser-width = window.inner-width + browser-height = window.inner-height + window-width = @refs.main.offset-width + window-height = @refs.main.offset-height + + # 動かした時 + drag-listen (me) ~> + move-left = me.client-x - move-base-x + move-top = me.client-y - move-base-y + + # 上はみ出し + if move-top < 0 + move-top = 0 + + # 左はみ出し + if move-left < 0 + move-left = 0 + + # 下はみ出し + if move-top + window-height > browser-height + move-top = browser-height - window-height + + # 右はみ出し + if move-left + window-width > browser-width + move-left = browser-width - window-width + + @refs.main.style.left = move-left + \px + @refs.main.style.top = move-top + \px + + # 上ハンドル掴み時 + @on-top-handle-mousedown = (e) ~> + e.prevent-default! + + base = e.client-y + height = parse-int((get-computed-style @refs.main, '').height, 10) + top = parse-int((get-computed-style @refs.main, '').top, 10) + + # 動かした時 + drag-listen (me) ~> + move = me.client-y - base + if top + move > 0 + if height + -move > @min-height + @apply-transform-height height + -move + @apply-transform-top top + move + else # 最小の高さより小さくなろうとした時 + @apply-transform-height @min-height + @apply-transform-top top + (height - @min-height) + else # 上のはみ出し時 + @apply-transform-height top + height + @apply-transform-top 0 + + # 右ハンドル掴み時 + @on-right-handle-mousedown = (e) ~> + e.prevent-default! + + base = e.client-x + width = parse-int((get-computed-style @refs.main, '').width, 10) + left = parse-int((get-computed-style @refs.main, '').left, 10) + browser-width = window.inner-width + + # 動かした時 + drag-listen (me) ~> + move = me.client-x - base + if left + width + move < browser-width + if width + move > @min-width + @apply-transform-width width + move + else # 最小の幅より小さくなろうとした時 + @apply-transform-width @min-width + else # 右のはみ出し時 + @apply-transform-width browser-width - left + + # 下ハンドル掴み時 + @on-bottom-handle-mousedown = (e) ~> + e.prevent-default! + + base = e.client-y + height = parse-int((get-computed-style @refs.main, '').height, 10) + top = parse-int((get-computed-style @refs.main, '').top, 10) + browser-height = window.inner-height + + # 動かした時 + drag-listen (me) ~> + move = me.client-y - base + if top + height + move < browser-height + if height + move > @min-height + @apply-transform-height height + move + else # 最小の高さより小さくなろうとした時 + @apply-transform-height @min-height + else # 下のはみ出し時 + @apply-transform-height browser-height - top + + # 左ハンドル掴み時 + @on-left-handle-mousedown = (e) ~> + e.prevent-default! + + base = e.client-x + width = parse-int((get-computed-style @refs.main, '').width, 10) + left = parse-int((get-computed-style @refs.main, '').left, 10) + + # 動かした時 + drag-listen (me) ~> + move = me.client-x - base + if left + move > 0 + if width + -move > @min-width + @apply-transform-width width + -move + @apply-transform-left left + move + else # 最小の幅より小さくなろうとした時 + @apply-transform-width @min-width + @apply-transform-left left + (width - @min-width) + else # 左のはみ出し時 + @apply-transform-width left + width + @apply-transform-left 0 + + # 左上ハンドル掴み時 + @on-top-left-handle-mousedown = (e) ~> + @on-top-handle-mousedown e + @on-left-handle-mousedown e + + # 右上ハンドル掴み時 + @on-top-right-handle-mousedown = (e) ~> + @on-top-handle-mousedown e + @on-right-handle-mousedown e + + # 右下ハンドル掴み時 + @on-bottom-right-handle-mousedown = (e) ~> + @on-bottom-handle-mousedown e + @on-right-handle-mousedown e + + # 左下ハンドル掴み時 + @on-bottom-left-handle-mousedown = (e) ~> + @on-bottom-handle-mousedown e + @on-left-handle-mousedown e + + # 高さを適用 + @apply-transform-height = (height) ~> + @refs.main.style.height = height + \px + + # 幅を適用 + @apply-transform-width = (width) ~> + @refs.main.style.width = width + \px + + # Y座標を適用 + @apply-transform-top = (top) ~> + @refs.main.style.top = top + \px + + # X座標を適用 + @apply-transform-left = (left) ~> + @refs.main.style.left = left + \px + + function drag-listen fn + window.add-event-listener \mousemove fn + window.add-event-listener \mouseleave drag-clear.bind null fn + window.add-event-listener \mouseup drag-clear.bind null fn + + function drag-clear fn + window.remove-event-listener \mousemove fn + window.remove-event-listener \mouseleave drag-clear + window.remove-event-listener \mouseup drag-clear + + @ondragover = (e) ~> + e.data-transfer.drop-effect = \none + + @on-keydown = (e) ~> + if e.which == 27 # Esc + if @can-close + e.prevent-default! + e.stop-propagation! + @close! + + function contains(parent, child) + node = child.parent-node + while node? + if node == parent + return true + node = node.parent-node + return false + </script> +</mk-window> diff --git a/src/web/app/dev/tags/new-app-form.tag b/src/web/app/dev/tags/new-app-form.tag index 443bf2bfff..c74a43d151 100644 --- a/src/web/app/dev/tags/new-app-form.tag +++ b/src/web/app/dev/tags/new-app-form.tag @@ -1,260 +1,243 @@ -mk-new-app-form - form(onsubmit={ onsubmit }, autocomplete='off') - section.name: label - p.caption - | アプリケーション名 - input@name( - type='text' - placeholder='ex) Misskey for iOS' - autocomplete='off' - required) - - section.nid: label - p.caption - | Named ID - input@nid( - type='text' - pattern='^[a-zA-Z0-9\-]{3,30}$' - placeholder='ex) misskey-for-ios' - autocomplete='off' - required - onkeyup={ on-change-nid }) - - p.info(if={ nid-state == 'wait' }, style='color:#999') - i.fa.fa-fw.fa-spinner.fa-pulse - | 確認しています... - p.info(if={ nid-state == 'ok' }, style='color:#3CB7B5') - i.fa.fa-fw.fa-check - | 利用できます - p.info(if={ nid-state == 'unavailable' }, style='color:#FF1161') - i.fa.fa-fw.fa-exclamation-triangle - | 既に利用されています - p.info(if={ nid-state == 'error' }, style='color:#FF1161') - i.fa.fa-fw.fa-exclamation-triangle - | 通信エラー - p.info(if={ nid-state == 'invalid-format' }, style='color:#FF1161') - i.fa.fa-fw.fa-exclamation-triangle - | a~z、A~Z、0~9、-(ハイフン)が使えます - p.info(if={ nid-state == 'min-range' }, style='color:#FF1161') - i.fa.fa-fw.fa-exclamation-triangle - | 3文字以上でお願いします! - p.info(if={ nid-state == 'max-range' }, style='color:#FF1161') - i.fa.fa-fw.fa-exclamation-triangle - | 30文字以内でお願いします - - section.description: label - p.caption - | アプリの概要 - textarea@description( - placeholder='ex) Misskey iOSクライアント。' - autocomplete='off' - required) - - section.callback: label - p.caption - | コールバックURL (オプション) - input@cb( - type='url' - placeholder='ex) https://your.app.example.com/callback.php' - autocomplete='off') - - section.permission - p.caption - | 権限 - div@permission - label - input(type='checkbox', value='account-read') - p アカウントの情報を見る。 - label - input(type='checkbox', value='account-write') - p アカウントの情報を操作する。 - label - input(type='checkbox', value='post-write') - p 投稿する。 - label - input(type='checkbox', value='like-write') - p いいねしたりいいね解除する。 - label - input(type='checkbox', value='following-write') - p フォローしたりフォロー解除する。 - label - input(type='checkbox', value='drive-read') - p ドライブを見る。 - label - input(type='checkbox', value='drive-write') - p ドライブを操作する。 - label - input(type='checkbox', value='notification-read') - p 通知を見る。 - label - input(type='checkbox', value='notification-write') - p 通知を操作する。 - p - i.fa.fa-exclamation-triangle - | アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。 - - button(onclick={ onsubmit }) - | アプリ作成 - -style. - display block - overflow hidden - - > form - - section +<mk-new-app-form> + <form onsubmit="{ onsubmit }" autocomplete="off"> + <section class="name"> + <label> + <p class="caption">アプリケーション名</p> + <input ref="name" type="text" placeholder="ex) Misskey for iOS" autocomplete="off" required="required"/> + </label> + </section> + <section class="nid"> + <label> + <p class="caption">Named ID</p> + <input ref="nid" type="text" pattern="^[a-zA-Z0-9-]{3,30}$" placeholder="ex) misskey-for-ios" autocomplete="off" required="required" onkeyup="{ onChangeNid }"/> + <p class="info" if="{ nidState == 'wait' }" style="color:#999"><i class="fa fa-fw fa-spinner fa-pulse"></i>確認しています...</p> + <p class="info" if="{ nidState == 'ok' }" style="color:#3CB7B5"><i class="fa fa-fw fa-check"></i>利用できます</p> + <p class="info" if="{ nidState == 'unavailable' }" style="color:#FF1161"><i class="fa fa-fw fa-exclamation-triangle"></i>既に利用されています</p> + <p class="info" if="{ nidState == 'error' }" style="color:#FF1161"><i class="fa fa-fw fa-exclamation-triangle"></i>通信エラー</p> + <p class="info" if="{ nidState == '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="{ nidState == 'min-range' }" style="color:#FF1161"><i class="fa fa-fw fa-exclamation-triangle"></i>3文字以上でお願いします!</p> + <p class="info" if="{ nidState == 'max-range' }" style="color:#FF1161"><i class="fa fa-fw fa-exclamation-triangle"></i>30文字以内でお願いします</p> + </label> + </section> + <section class="description"> + <label> + <p class="caption">アプリの概要</p> + <textarea ref="description" placeholder="ex) Misskey iOSクライアント。" autocomplete="off" required="required"></textarea> + </label> + </section> + <section class="callback"> + <label> + <p class="caption">コールバックURL (オプション)</p> + <input ref="cb" type="url" placeholder="ex) https://your.app.example.com/callback.php" autocomplete="off"/> + </label> + </section> + <section class="permission"> + <p class="caption">権限</p> + <div ref="permission"> + <label> + <input type="checkbox" value="account-read"/> + <p>アカウントの情報を見る。</p> + </label> + <label> + <input type="checkbox" value="account-write"/> + <p>アカウントの情報を操作する。</p> + </label> + <label> + <input type="checkbox" value="post-write"/> + <p>投稿する。</p> + </label> + <label> + <input type="checkbox" value="like-write"/> + <p>いいねしたりいいね解除する。</p> + </label> + <label> + <input type="checkbox" value="following-write"/> + <p>フォローしたりフォロー解除する。</p> + </label> + <label> + <input type="checkbox" value="drive-read"/> + <p>ドライブを見る。</p> + </label> + <label> + <input type="checkbox" value="drive-write"/> + <p>ドライブを操作する。</p> + </label> + <label> + <input type="checkbox" value="notification-read"/> + <p>通知を見る。</p> + </label> + <label> + <input type="checkbox" value="notification-write"/> + <p>通知を操作する。</p> + </label> + </div> + <p><i class="fa fa-exclamation-triangle"></i>アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。</p> + </section> + <button onclick="{ onsubmit }">アプリ作成</button> + </form> + <style type="stylus"> + :scope display block - margin 16px 0 + overflow hidden - .caption - margin 0 0 4px 0 - color #616161 - font-size 0.95em + > form - > i - margin-right 0.25em - color #96adac + section + display block + margin 16px 0 - .info - display block - margin 4px 0 - font-size 0.8em + .caption + margin 0 0 4px 0 + color #616161 + font-size 0.95em - > i - margin-right 0.3em + > i + margin-right 0.25em + color #96adac - section.permission - div - padding 8px 0 - max-height 160px - overflow auto - background #fff - border solid 1px #cecece - border-radius 4px + .info + display block + margin 4px 0 + font-size 0.8em - label - display block - padding 0 12px - line-height 32px - cursor pointer + > i + margin-right 0.3em - &:hover - > p + section.permission + div + padding 8px 0 + max-height 160px + overflow auto + background #fff + border solid 1px #cecece + border-radius 4px + + label + display block + padding 0 12px + line-height 32px + cursor pointer + + &:hover + > p + color #999 + + [type='checkbox']:checked + p + color #000 + + [type='checkbox'] + margin-right 4px + + [type='checkbox']:checked + p + color #111 + + > p + display inline + color #aaa + user-select none + + > p:last-child + margin 6px + font-size 0.8em color #999 - [type='checkbox']:checked + p - color #000 + > i + margin-right 4px - [type='checkbox'] - margin-right 4px + [type=text] + [type=url] + textarea + user-select text + display inline-block + cursor auto + padding 8px 12px + margin 0 + width 100% + font-size 1em + color #333 + background #fff + outline none + border solid 1px #cecece + border-radius 4px - [type='checkbox']:checked + p + &:hover + border-color #bbb + + &:focus + border-color $theme-color + + &:disabled + opacity 0.5 + + > button + margin 20px 0 32px 0 + width 100% + font-size 1em color #111 + border-radius 3px - > p - display inline - color #aaa - user-select none + </style> + <script> + @mixin \api - > p:last-child - margin 6px - font-size 0.8em - color #999 + @nid-state = null - > i - margin-right 4px + @on-change-nid = ~> + nid = @refs.nid.value - [type=text] - [type=url] - textarea - user-select text - display inline-block - cursor auto - padding 8px 12px - margin 0 - width 100% - font-size 1em - color #333 - background #fff - outline none - border solid 1px #cecece - border-radius 4px + if nid == '' + @nid-state = null + @update! + return - &:hover - border-color #bbb + err = switch + | not nid.match /^[a-zA-Z0-9\-]+$/ => \invalid-format + | nid.length < 3chars => \min-range + | nid.length > 30chars => \max-range + | _ => null - &:focus - border-color $theme-color + if err? + @nid-state = err + @update! + else + @nid-state = \wait + @update! - &:disabled - opacity 0.5 + @api \app/name_id/available do + name_id: nid + .then (result) ~> + if result.available + @nid-state = \ok + else + @nid-state = \unavailable + @update! + .catch (err) ~> + @nid-state = \error + @update! - > button - margin 20px 0 32px 0 - width 100% - font-size 1em - color #111 - border-radius 3px + @onsubmit = ~> + name = @refs.name.value + nid = @refs.nid.value + description = @refs.description.value + cb = @refs.cb.value + permission = [] -script. - @mixin \api + @refs.permission.query-selector-all \input .for-each (el) ~> + if el.checked then permission.push el.value - @nid-state = null + locker = document.body.append-child document.create-element \mk-locker - @on-change-nid = ~> - nid = @refs.nid.value - - if nid == '' - @nid-state = null - @update! - return - - err = switch - | not nid.match /^[a-zA-Z0-9\-]+$/ => \invalid-format - | nid.length < 3chars => \min-range - | nid.length > 30chars => \max-range - | _ => null - - if err? - @nid-state = err - @update! - else - @nid-state = \wait - @update! - - @api \app/name_id/available do + @api \app/create do + name: name name_id: nid - .then (result) ~> - if result.available - @nid-state = \ok - else - @nid-state = \unavailable - @update! - .catch (err) ~> - @nid-state = \error - @update! + description: description + callback_url: cb + permission: permission.join \, + .then ~> + location.href = '/apps' + .catch ~> + alert 'アプリの作成に失敗しました。再度お試しください。' - @onsubmit = ~> - name = @refs.name.value - nid = @refs.nid.value - description = @refs.description.value - cb = @refs.cb.value - permission = [] - - @refs.permission.query-selector-all \input .for-each (el) ~> - if el.checked then permission.push el.value - - locker = document.body.append-child document.create-element \mk-locker - - @api \app/create do - name: name - name_id: nid - description: description - callback_url: cb - permission: permission.join \, - .then ~> - location.href = '/apps' - .catch ~> - alert 'アプリの作成に失敗しました。再度お試しください。' - - locker.parent-node.remove-child locker + locker.parent-node.remove-child locker + </script> +</mk-new-app-form> diff --git a/src/web/app/dev/tags/pages/app.tag b/src/web/app/dev/tags/pages/app.tag index aa9ba68f3f..4311f11565 100644 --- a/src/web/app/dev/tags/pages/app.tag +++ b/src/web/app/dev/tags/pages/app.tag @@ -1,24 +1,30 @@ -mk-app-page - p(if={ fetching }) 読み込み中 - main(if={ !fetching }) - header - h1 { app.name } - div.body - p App Secret - input(value={ app.secret }, readonly) +<mk-app-page> + <p if="{ fetching }">読み込み中</p> + <main if="{ !fetching }"> + <header> + <h1>{ app.name }</h1> + </header> + <div class="body"> + <p>App Secret</p> + <input value="{ app.secret }" readonly="readonly"/> + </div> + </main> + <style type="stylus"> + :scope + display block -style. - display block + </style> + <script> + @mixin \api -script. - @mixin \api + @fetching = true - @fetching = true - - @on \mount ~> - @api \app/show do - app_id: @opts.app - .then (app) ~> - @app = app - @fetching = false - @update! + @on \mount ~> + @api \app/show do + app_id: @opts.app + .then (app) ~> + @app = app + @fetching = false + @update! + </script> +</mk-app-page> diff --git a/src/web/app/dev/tags/pages/apps.tag b/src/web/app/dev/tags/pages/apps.tag index f46a9d3282..b7eb441faa 100644 --- a/src/web/app/dev/tags/pages/apps.tag +++ b/src/web/app/dev/tags/pages/apps.tag @@ -1,26 +1,30 @@ -mk-apps-page - h1 アプリを管理 - a(href='/app/new') アプリ作成 - div.apps - p(if={ fetching }) 読み込み中 - virtual(if={ !fetching }) - p(if={ apps.length == 0 }) アプリなし - ul(if={ apps.length > 0 }) - li(each={ app in apps }) - a(href={ '/app/' + app.id }) - p.name { app.name } +<mk-apps-page> + <h1>アプリを管理</h1><a href="/app/new">アプリ作成</a> + <div class="apps"> + <p if="{ fetching }">読み込み中</p> + <virtual if="{ !fetching }"> + <p if="{ apps.length == 0 }">アプリなし</p> + <ul if="{ apps.length > 0 }"> + <li each="{ app in apps }"><a href="{ '/app/' + app.id }"> + <p class="name">{ app.name }</p></a></li> + </ul> + </virtual> + </div> + <style type="stylus"> + :scope + display block -style. - display block + </style> + <script> + @mixin \api -script. - @mixin \api + @fetching = true - @fetching = true - - @on \mount ~> - @api \my/apps - .then (apps) ~> - @fetching = false - @apps = apps - @update! + @on \mount ~> + @api \my/apps + .then (apps) ~> + @fetching = false + @apps = apps + @update! + </script> +</mk-apps-page> diff --git a/src/web/app/dev/tags/pages/index.tag b/src/web/app/dev/tags/pages/index.tag index 7bc57fbb00..6be52e61ba 100644 --- a/src/web/app/dev/tags/pages/index.tag +++ b/src/web/app/dev/tags/pages/index.tag @@ -1,5 +1,11 @@ -mk-index - a(href='/apps') アプリ +<mk-index><a href="/apps">アプリ</a> + <style type="stylus"> + :scope + display block -style. - display block + + + + + </style> +</mk-index> diff --git a/src/web/app/dev/tags/pages/new-app.tag b/src/web/app/dev/tags/pages/new-app.tag index 8c19e39f4b..f255b84328 100644 --- a/src/web/app/dev/tags/pages/new-app.tag +++ b/src/web/app/dev/tags/pages/new-app.tag @@ -1,33 +1,42 @@ -mk-new-app-page - main - header - h1 新しいアプリを作成 - p MisskeyのAPIを利用したアプリケーションを作成できます。 - mk-new-app-form +<mk-new-app-page> + <main> + <header> + <h1>新しいアプリを作成</h1> + <p>MisskeyのAPIを利用したアプリケーションを作成できます。</p> + </header> + <mk-new-app-form></mk-new-app-form> + </main> + <style type="stylus"> + :scope + display block + padding 64px 0 -style. - display block - padding 64px 0 + > main + width 100% + max-width 700px + margin 0 auto - > main - width 100% - max-width 700px - margin 0 auto + > header + margin 0 0 16px 0 + padding 0 0 16px 0 + border-bottom solid 1px #282827 - > header - margin 0 0 16px 0 - padding 0 0 16px 0 - border-bottom solid 1px #282827 + > h1 + margin 0 0 12px 0 + padding 0 + line-height 32px + font-size 32px + font-weight normal + color #000 - > h1 - margin 0 0 12px 0 - padding 0 - line-height 32px - font-size 32px - font-weight normal - color #000 + > p + margin 0 + line-height 16px + color #9a9894 - > p - margin 0 - line-height 16px - color #9a9894 + + + + + </style> +</mk-new-app-page> diff --git a/src/web/app/mobile/tags/drive-selector.tag b/src/web/app/mobile/tags/drive-selector.tag index 442299026e..f4fd24326f 100644 --- a/src/web/app/mobile/tags/drive-selector.tag +++ b/src/web/app/mobile/tags/drive-selector.tag @@ -1,75 +1,78 @@ -mk-drive-selector - div.body - header - h1 - | ファイルを選択 - span.count(if={ files.length > 0 }) ({ files.length }) - button.close(onclick={ cancel }): i.fa.fa-times - button.ok(onclick={ ok }): i.fa.fa-check - mk-drive@browser(select={ true }, multiple={ opts.multiple }) +<mk-drive-selector> + <div class="body"> + <header> + <h1>ファイルを選択<span class="count" if="{ files.length > 0 }">({ files.length })</span></h1> + <button class="close" onclick="{ cancel }"><i class="fa fa-times"></i></button> + <button class="ok" onclick="{ ok }"><i class="fa fa-check"></i></button> + </header> + <mk-drive ref="browser" select="{ true }" multiple="{ opts.multiple }"></mk-drive> + </div> + <style type="stylus"> + :scope + display block -style. - display block - - > .body - position fixed - z-index 2048 - top 0 - left 0 - right 0 - margin 0 auto - width 100% - max-width 500px - height 100% - overflow hidden - background #fff - box-shadow 0 0 16px rgba(#000, 0.3) - - > header - border-bottom solid 1px #eee - - > h1 - margin 0 - padding 0 - text-align center - line-height 42px - font-size 1em - font-weight normal - - > .count - margin-left 4px - opacity 0.5 - - > .close - position absolute + > .body + position fixed + z-index 2048 top 0 left 0 - line-height 42px - width 42px - - > .ok - position absolute - top 0 right 0 - line-height 42px - width 42px + margin 0 auto + width 100% + max-width 500px + height 100% + overflow hidden + background #fff + box-shadow 0 0 16px rgba(#000, 0.3) - > mk-drive - height calc(100% - 42px) - overflow scroll + > header + border-bottom solid 1px #eee -script. - @files = [] + > h1 + margin 0 + padding 0 + text-align center + line-height 42px + font-size 1em + font-weight normal - @on \mount ~> - @refs.browser.on \change-selected (files) ~> - @files = files - @update! + > .count + margin-left 4px + opacity 0.5 - @cancel = ~> - @trigger \canceled - @unmount! + > .close + position absolute + top 0 + left 0 + line-height 42px + width 42px - @ok = ~> - @trigger \selected @files - @unmount! + > .ok + position absolute + top 0 + right 0 + line-height 42px + width 42px + + > mk-drive + height calc(100% - 42px) + overflow scroll + + </style> + <script> + @files = [] + + @on \mount ~> + @refs.browser.on \change-selected (files) ~> + @files = files + @update! + + @cancel = ~> + @trigger \canceled + @unmount! + + @ok = ~> + @trigger \selected @files + @unmount! + </script> +</mk-drive-selector> diff --git a/src/web/app/mobile/tags/drive.tag b/src/web/app/mobile/tags/drive.tag index fcc78d1e68..005f16d58f 100644 --- a/src/web/app/mobile/tags/drive.tag +++ b/src/web/app/mobile/tags/drive.tag @@ -1,338 +1,342 @@ -mk-drive - nav - p(onclick={ go-root }) - i.fa.fa-cloud - | ドライブ - virtual(each={ folder in hierarchy-folders }) - span: i.fa.fa-angle-right - p(onclick={ _move }) { folder.name } - span(if={ folder != null }): i.fa.fa-angle-right - p(if={ folder != null }) { folder.name } - div.browser(if={ file == null }, class={ loading: loading }) - div.folders(if={ folders.length > 0 }) - virtual(each={ folder in folders }) - mk-drive-folder(folder={ folder }) - p(if={ more-folders }) - | もっと読み込む - div.files(if={ files.length > 0 }) - virtual(each={ file in files }) - mk-drive-file(file={ file }) - p(if={ more-files }) - | もっと読み込む - div.empty(if={ files.length == 0 && folders.length == 0 && !loading }) - p(if={ !folder == null }) - | ドライブには何もありません。 - p(if={ folder != null }) - | このフォルダーは空です - div.loading(if={ loading }). +<mk-drive> + <nav> + <p onclick="{ goRoot }"><i class="fa fa-cloud"></i>ドライブ</p> + <virtual each="{ folder in hierarchyFolders }"><span><i class="fa fa-angle-right"></i></span> + <p onclick="{ _move }">{ folder.name }</p> + </virtual><span if="{ folder != null }"><i class="fa fa-angle-right"></i></span> + <p if="{ folder != null }">{ folder.name }</p> + </nav> + <div class="browser { loading: loading }" if="{ file == null }"> + <div class="folders" if="{ folders.length > 0 }"> + <virtual each="{ folder in folders }"> + <mk-drive-folder folder="{ folder }"></mk-drive-folder> + </virtual> + <p if="{ moreFolders }">もっと読み込む</p> + </div> + <div class="files" if="{ files.length > 0 }"> + <virtual each="{ file in files }"> + <mk-drive-file file="{ file }"></mk-drive-file> + </virtual> + <p if="{ moreFiles }">もっと読み込む</p> + </div> + <div class="empty" if="{ files.length == 0 && folders.length == 0 && !loading }"> + <p if="{ !folder == null }">ドライブには何もありません。</p> + <p if="{ folder != null }">このフォルダーは空です</p> + </div> + <div class="loading" if="{ loading }"> <div class="spinner"> <div class="dot1"></div> <div class="dot2"></div> </div> - mk-drive-file-viewer(if={ file != null }, file={ file }) + </div> + </div> + <mk-drive-file-viewer if="{ file != null }" file="{ file }"></mk-drive-file-viewer> + <style type="stylus"> + :scope + display block + background #fff -style. - display block - background #fff + > nav + display block + width 100% + padding 10px 12px + overflow auto + white-space nowrap + font-size 0.9em + color #555 + background #fff + border-bottom solid 1px #dfdfdf - > nav - display block - width 100% - padding 10px 12px - overflow auto - white-space nowrap - font-size 0.9em - color #555 - background #fff - border-bottom solid 1px #dfdfdf + > p + display inline + margin 0 + padding 0 - > p - display inline - margin 0 - padding 0 + &:last-child + font-weight bold - &:last-child - font-weight bold + > i + margin-right 4px - > i - margin-right 4px + > span + margin 0 8px + opacity 0.5 - > span - margin 0 8px - opacity 0.5 + > .browser + &.loading + opacity 0.5 - > .browser - &.loading - opacity 0.5 + > .folders + > mk-drive-folder + border-bottom solid 1px #eee - > .folders - > mk-drive-folder - border-bottom solid 1px #eee + > .files + > mk-drive-file + border-bottom solid 1px #eee - > .files - > mk-drive-file - border-bottom solid 1px #eee + > .empty + padding 16px + text-align center + color #999 + pointer-events none - > .empty - padding 16px - text-align center - color #999 - pointer-events none + > p + margin 0 - > p - margin 0 + > .loading + .spinner + margin 100px auto + width 40px + height 40px + text-align center - > .loading - .spinner - margin 100px auto - width 40px - height 40px - text-align center + animation sk-rotate 2.0s infinite linear - animation sk-rotate 2.0s infinite linear + .dot1, .dot2 + width 60% + height 60% + display inline-block + position absolute + top 0 + background-color rgba(0, 0, 0, 0.3) + border-radius 100% - .dot1, .dot2 - width 60% - height 60% - display inline-block - position absolute - top 0 - background-color rgba(0, 0, 0, 0.3) - border-radius 100% + animation sk-bounce 2.0s infinite ease-in-out - animation sk-bounce 2.0s infinite ease-in-out + .dot2 + top auto + bottom 0 + animation-delay -1.0s - .dot2 - top auto - bottom 0 - animation-delay -1.0s + @keyframes sk-rotate { 100% { transform: rotate(360deg); }} - @keyframes sk-rotate { 100% { transform: rotate(360deg); }} + @keyframes sk-bounce { + 0%, 100% { + transform: scale(0.0); + } 50% { + transform: scale(1.0); + } + } - @keyframes sk-bounce { - 0%, 100% { - transform: scale(0.0); - } 50% { - transform: scale(1.0); - } - } + </style> + <script> + @mixin \api + @mixin \stream -script. - @mixin \api - @mixin \stream + @files = [] + @folders = [] + @hierarchy-folders = [] + @selected-files = [] - @files = [] - @folders = [] - @hierarchy-folders = [] - @selected-files = [] + # 現在の階層(フォルダ) + # * null でルートを表す + @folder = null - # 現在の階層(フォルダ) - # * null でルートを表す - @folder = null + @file = null - @file = null + @is-select-mode = @opts.select? and @opts.select + @multiple = if @opts.multiple? then @opts.multiple else false - @is-select-mode = @opts.select? and @opts.select - @multiple = if @opts.multiple? then @opts.multiple else false + @on \mount ~> + @stream.on \drive_file_created @on-stream-drive-file-created + @stream.on \drive_file_updated @on-stream-drive-file-updated + @stream.on \drive_folder_created @on-stream-drive-folder-created + @stream.on \drive_folder_updated @on-stream-drive-folder-updated - @on \mount ~> - @stream.on \drive_file_created @on-stream-drive-file-created - @stream.on \drive_file_updated @on-stream-drive-file-updated - @stream.on \drive_folder_created @on-stream-drive-folder-created - @stream.on \drive_folder_updated @on-stream-drive-folder-updated + # Riotのバグでnullを渡しても""になる + # https://github.com/riot/riot/issues/2080 + #if @opts.folder? + if @opts.folder? and @opts.folder != '' + @cd @opts.folder + else + @load! - # Riotのバグでnullを渡しても""になる - # https://github.com/riot/riot/issues/2080 - #if @opts.folder? - if @opts.folder? and @opts.folder != '' - @cd @opts.folder - else - @load! + @on \unmount ~> + @stream.off \drive_file_created @on-stream-drive-file-created + @stream.off \drive_file_updated @on-stream-drive-file-updated + @stream.off \drive_folder_created @on-stream-drive-folder-created + @stream.off \drive_folder_updated @on-stream-drive-folder-updated - @on \unmount ~> - @stream.off \drive_file_created @on-stream-drive-file-created - @stream.off \drive_file_updated @on-stream-drive-file-updated - @stream.off \drive_folder_created @on-stream-drive-folder-created - @stream.off \drive_folder_updated @on-stream-drive-folder-updated - - @on-stream-drive-file-created = (file) ~> - @add-file file, true - - @on-stream-drive-file-updated = (file) ~> - current = if @folder? then @folder.id else null - if current != file.folder_id - @remove-file file - else + @on-stream-drive-file-created = (file) ~> @add-file file, true - @on-stream-drive-folder-created = (folder) ~> - @add-folder folder, true + @on-stream-drive-file-updated = (file) ~> + current = if @folder? then @folder.id else null + if current != file.folder_id + @remove-file file + else + @add-file file, true - @on-stream-drive-folder-updated = (folder) ~> - current = if @folder? then @folder.id else null - if current != folder.parent_id - @remove-folder folder - else + @on-stream-drive-folder-created = (folder) ~> @add-folder folder, true - @_move = (ev) ~> - @move ev.item.folder + @on-stream-drive-folder-updated = (folder) ~> + current = if @folder? then @folder.id else null + if current != folder.parent_id + @remove-folder folder + else + @add-folder folder, true - @move = (target-folder) ~> - @cd target-folder, true + @_move = (ev) ~> + @move ev.item.folder - @cd = (target-folder, is-move) ~> - if target-folder? and typeof target-folder == \object - target-folder = target-folder.id + @move = (target-folder) ~> + @cd target-folder, true - if target-folder == null - @go-root! - return + @cd = (target-folder, is-move) ~> + if target-folder? and typeof target-folder == \object + target-folder = target-folder.id - @loading = true - @update! - - @api \drive/folders/show do - folder_id: target-folder - .then (folder) ~> - @folder = folder - @hierarchy-folders = [] - - x = (f) ~> - @hierarchy-folders.unshift f - if f.parent? - x f.parent - - if folder.parent? - x folder.parent + if target-folder == null + @go-root! + return + @loading = true @update! - if is-move then @trigger \move @folder - @trigger \cd @folder - @load! - .catch (err, text-status) -> - console.error err - @add-folder = (folder, unshift = false) ~> - current = if @folder? then @folder.id else null - if current != folder.parent_id - return + @api \drive/folders/show do + folder_id: target-folder + .then (folder) ~> + @folder = folder + @hierarchy-folders = [] - if (@folders.some (f) ~> f.id == folder.id) - return + x = (f) ~> + @hierarchy-folders.unshift f + if f.parent? + x f.parent - if unshift - @folders.unshift folder - else - @folders.push folder + if folder.parent? + x folder.parent - @update! - - @add-file = (file, unshift = false) ~> - current = if @folder? then @folder.id else null - if current != file.folder_id - return - - if (@files.some (f) ~> f.id == file.id) - exist = (@files.map (f) -> f.id).index-of file.id - @files[exist] = file - @update! - return - - if unshift - @files.unshift file - else - @files.push file - - @update! - - @remove-folder = (folder) ~> - if typeof folder == \object - folder = folder.id - @folders = @folders.filter (f) -> f.id != folder - @update! - - @remove-file = (file) ~> - if typeof file == \object - file = file.id - @files = @files.filter (f) -> f.id != file - @update! - - @go-root = ~> - if @folder != null - @folder = null - @hierarchy-folders = [] - @update! - @trigger \move-root - @load! - - @load = ~> - @folders = [] - @files = [] - @more-folders = false - @more-files = false - @loading = true - @update! - - @trigger \begin-load - - load-folders = null - load-files = null - - folders-max = 20 - files-max = 20 - - # フォルダ一覧取得 - @api \drive/folders do - folder_id: if @folder? then @folder.id else null - limit: folders-max + 1 - .then (folders) ~> - if folders.length == folders-max + 1 - @more-folders = true - folders.pop! - load-folders := folders - complete! - .catch (err, text-status) ~> - console.error err - - # ファイル一覧取得 - @api \drive/files do - folder_id: if @folder? then @folder.id else null - limit: files-max + 1 - .then (files) ~> - if files.length == files-max + 1 - @more-files = true - files.pop! - load-files := files - complete! - .catch (err, text-status) ~> - console.error err - - flag = false - complete = ~> - if flag - load-folders.for-each (folder) ~> - @add-folder folder - load-files.for-each (file) ~> - @add-file file - @loading = false @update! + if is-move then @trigger \move @folder + @trigger \cd @folder + @load! + .catch (err, text-status) -> + console.error err - @trigger \loaded - else - flag := true - @trigger \load-mid + @add-folder = (folder, unshift = false) ~> + current = if @folder? then @folder.id else null + if current != folder.parent_id + return - @choose-file = (file) ~> - if @is-select-mode - exist = @selected-files.some (f) ~> f.id == file.id - if exist - @selected-files = (@selected-files.filter (f) ~> f.id != file.id) + if (@folders.some (f) ~> f.id == folder.id) + return + + if unshift + @folders.unshift folder else - @selected-files.push file + @folders.push folder + @update! - @trigger \change-selected @selected-files - else - @file = file + + @add-file = (file, unshift = false) ~> + current = if @folder? then @folder.id else null + if current != file.folder_id + return + + if (@files.some (f) ~> f.id == file.id) + exist = (@files.map (f) -> f.id).index-of file.id + @files[exist] = file + @update! + return + + if unshift + @files.unshift file + else + @files.push file + @update! - @trigger \open-file @file + + @remove-folder = (folder) ~> + if typeof folder == \object + folder = folder.id + @folders = @folders.filter (f) -> f.id != folder + @update! + + @remove-file = (file) ~> + if typeof file == \object + file = file.id + @files = @files.filter (f) -> f.id != file + @update! + + @go-root = ~> + if @folder != null + @folder = null + @hierarchy-folders = [] + @update! + @trigger \move-root + @load! + + @load = ~> + @folders = [] + @files = [] + @more-folders = false + @more-files = false + @loading = true + @update! + + @trigger \begin-load + + load-folders = null + load-files = null + + folders-max = 20 + files-max = 20 + + # フォルダ一覧取得 + @api \drive/folders do + folder_id: if @folder? then @folder.id else null + limit: folders-max + 1 + .then (folders) ~> + if folders.length == folders-max + 1 + @more-folders = true + folders.pop! + load-folders := folders + complete! + .catch (err, text-status) ~> + console.error err + + # ファイル一覧取得 + @api \drive/files do + folder_id: if @folder? then @folder.id else null + limit: files-max + 1 + .then (files) ~> + if files.length == files-max + 1 + @more-files = true + files.pop! + load-files := files + complete! + .catch (err, text-status) ~> + console.error err + + flag = false + complete = ~> + if flag + load-folders.for-each (folder) ~> + @add-folder folder + load-files.for-each (file) ~> + @add-file file + @loading = false + @update! + + @trigger \loaded + else + flag := true + @trigger \load-mid + + @choose-file = (file) ~> + if @is-select-mode + exist = @selected-files.some (f) ~> f.id == file.id + if exist + @selected-files = (@selected-files.filter (f) ~> f.id != file.id) + else + @selected-files.push file + @update! + @trigger \change-selected @selected-files + else + @file = file + @update! + @trigger \open-file @file + </script> +</mk-drive> diff --git a/src/web/app/mobile/tags/drive/file-viewer.tag b/src/web/app/mobile/tags/drive/file-viewer.tag index 8ce89a06f4..ac426278b3 100644 --- a/src/web/app/mobile/tags/drive/file-viewer.tag +++ b/src/web/app/mobile/tags/drive/file-viewer.tag @@ -1,8 +1,9 @@ -mk-drive-file-viewer - p.name { file.name } +<mk-drive-file-viewer> + <p class="name">{ file.name }</p> + <style type="stylus"> + :scope + display block -style. - display block - -script. - @file = @opts.file + </style> + <script>@file = @opts.file</script> +</mk-drive-file-viewer> diff --git a/src/web/app/mobile/tags/drive/file.tag b/src/web/app/mobile/tags/drive/file.tag index ec271441a5..3a2aa87731 100644 --- a/src/web/app/mobile/tags/drive/file.tag +++ b/src/web/app/mobile/tags/drive/file.tag @@ -1,130 +1,137 @@ -mk-drive-file(onclick={ onclick }, data-is-selected={ is-selected }) - div.container - div.thumbnail(style={ 'background-image: url(' + file.url + '?thumbnail&size=128)' }) - div.body - p.name { file.name } - // - if file.tags.length > 0 - ul.tags - each tag in file.tags - li.tag(style={background: tag.color, color: contrast(tag.color)})= tag.name - footer - p.type - mk-file-type-icon(file={ file }) - | { file.type } - p.separator - p.data-size { bytes-to-size(file.datasize) } - p.separator - p.created-at - i.fa.fa-clock-o - mk-time(time={ file.created_at }) - -style. - display block - - &, * - user-select none - - * - pointer-events none - - > .container - max-width 500px - margin 0 auto - padding 16px - - &:after - content "" +<mk-drive-file onclick="{ onclick }" data-is-selected="{ isSelected }"> + <div class="container"> + <div class="thumbnail" style="{ 'background-image: url(' + file.url + '?thumbnail&size=128)' }"></div> + <div class="body"> + <p class="name">{ file.name }</p> + <!-- + if file.tags.length > 0 + ul.tags + each tag in file.tags + li.tag(style="{background: tag.color, color: contrast(tag.color)}")= tag.name + --> + <footer> + <p class="type"> + <mk-file-type-icon file="{ file }"></mk-file-type-icon>{ file.type } + </p> + <p class="separator"></p> + <p class="data-size">{ bytesToSize(file.datasize) }</p> + <p class="separator"></p> + <p class="created-at"><i class="fa fa-clock-o"></i> + <mk-time time="{ file.created_at }"></mk-time> + </p> + </footer> + </div> + </div> + <style type="stylus"> + :scope display block - clear both - > .thumbnail - display block - float left - width 64px - height 64px - background-size cover - background-position center center + &, * + user-select none - > .body - display block - float left - width calc(100% - 74px) - margin-left 10px + * + pointer-events none - > .name - display block - margin 0 - padding 0 - font-size 0.9em - font-weight bold - color #555 - text-overflow ellipsis - word-wrap break-word + > .container + max-width 500px + margin 0 auto + padding 16px - > .tags - display block - margin 4px 0 0 0 - padding 0 - list-style none - font-size 0.5em + &:after + content "" + display block + clear both - > .tag - display inline-block - margin 0 5px 0 0 - padding 1px 5px - border-radius 2px + > .thumbnail + display block + float left + width 64px + height 64px + background-size cover + background-position center center - > footer - display block - margin 4px 0 0 0 - font-size 0.7em + > .body + display block + float left + width calc(100% - 74px) + margin-left 10px - > .separator - display inline - margin 0 - padding 0 4px - color #CDCDCD + > .name + display block + margin 0 + padding 0 + font-size 0.9em + font-weight bold + color #555 + text-overflow ellipsis + word-wrap break-word - > .type - display inline - margin 0 - padding 0 - color #9D9D9D + > .tags + display block + margin 4px 0 0 0 + padding 0 + list-style none + font-size 0.5em - > mk-file-type-icon - margin-right 4px + > .tag + display inline-block + margin 0 5px 0 0 + padding 1px 5px + border-radius 2px - > .data-size - display inline - margin 0 - padding 0 - color #9D9D9D + > footer + display block + margin 4px 0 0 0 + font-size 0.7em - > .created-at - display inline - margin 0 - padding 0 - color #BDBDBD + > .separator + display inline + margin 0 + padding 0 4px + color #CDCDCD - > i - margin-right 2px + > .type + display inline + margin 0 + padding 0 + color #9D9D9D - &[data-is-selected] - background $theme-color + > mk-file-type-icon + margin-right 4px - &, * - color #fff !important + > .data-size + display inline + margin 0 + padding 0 + color #9D9D9D -script. - @mixin \bytes-to-size + > .created-at + display inline + margin 0 + padding 0 + color #BDBDBD - @browser = @parent - @file = @opts.file - @is-selected = @browser.selected-files.some (f) ~> f.id == @file.id + > i + margin-right 2px - @browser.on \change-selected (selects) ~> - @is-selected = selects.some (f) ~> f.id == @file.id + &[data-is-selected] + background $theme-color - @onclick = ~> - @browser.choose-file @file + &, * + color #fff !important + + </style> + <script> + @mixin \bytes-to-size + + @browser = @parent + @file = @opts.file + @is-selected = @browser.selected-files.some (f) ~> f.id == @file.id + + @browser.on \change-selected (selects) ~> + @is-selected = selects.some (f) ~> f.id == @file.id + + @onclick = ~> + @browser.choose-file @file + </script> +</mk-drive-file> diff --git a/src/web/app/mobile/tags/drive/folder.tag b/src/web/app/mobile/tags/drive/folder.tag index ef3a72ea93..5a13686d4f 100644 --- a/src/web/app/mobile/tags/drive/folder.tag +++ b/src/web/app/mobile/tags/drive/folder.tag @@ -1,45 +1,46 @@ -mk-drive-folder(onclick={ onclick }) - div.container - p.name - i.fa.fa-folder - | { folder.name } - i.fa.fa-angle-right - -style. - display block - color #777 - - &, * - user-select none - - * - pointer-events none - - > .container - max-width 500px - margin 0 auto - padding 16px - - > .name +<mk-drive-folder onclick="{ onclick }"> + <div class="container"> + <p class="name"><i class="fa fa-folder"></i>{ folder.name }</p><i class="fa fa-angle-right"></i> + </div> + <style type="stylus"> + :scope display block - margin 0 - padding 0 + color #777 - > i - margin-right 6px + &, * + user-select none - > i - position absolute - top 0 - bottom 0 - right 8px - margin auto 0 auto 0 - width 1em - height 1em + * + pointer-events none -script. - @browser = @parent - @folder = @opts.folder + > .container + max-width 500px + margin 0 auto + padding 16px - @onclick = ~> - @browser.move @folder + > .name + display block + margin 0 + padding 0 + + > i + margin-right 6px + + > i + position absolute + top 0 + bottom 0 + right 8px + margin auto 0 auto 0 + width 1em + height 1em + + </style> + <script> + @browser = @parent + @folder = @opts.folder + + @onclick = ~> + @browser.move @folder + </script> +</mk-drive-folder> diff --git a/src/web/app/mobile/tags/follow-button.tag b/src/web/app/mobile/tags/follow-button.tag index 7cedbbee88..d44fd3b79b 100644 --- a/src/web/app/mobile/tags/follow-button.tag +++ b/src/web/app/mobile/tags/follow-button.tag @@ -1,108 +1,105 @@ -mk-follow-button - button(if={ !init }, class={ wait: wait, follow: !user.is_following, unfollow: user.is_following }, - onclick={ onclick }, - disabled={ wait }) - 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 }) - | { user.is_following ? 'フォロー解除' : 'フォロー' } - 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 }"><i class="fa fa-minus" if="{ !wait && user.is_following }"></i><i class="fa fa-plus" if="{ !wait && !user.is_following }"></i><i class="fa fa-spinner fa-pulse fa-fw" if="{ wait }"></i>{ user.is_following ? 'フォロー解除' : 'フォロー' }</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 + user-select none + cursor pointer + padding 0 16px + margin 0 + height inherit + font-size 16px + outline none + border solid 1px $theme-color + border-radius 4px - > button - > .init - display block - user-select none - cursor pointer - padding 0 16px - margin 0 - height inherit - font-size 16px - outline none - border solid 1px $theme-color - border-radius 4px + * + pointer-events none - * - pointer-events none + &.follow + color $theme-color + background transparent - &.follow - color $theme-color - background transparent + &:hover + background rgba($theme-color, 0.1) - &:hover - background rgba($theme-color, 0.1) + &:active + background rgba($theme-color, 0.2) - &:active - background rgba($theme-color, 0.2) + &.unfollow + color $theme-color-foreground + background $theme-color - &.unfollow - color $theme-color-foreground - background $theme-color + &.wait + cursor wait !important + opacity 0.7 - &.wait - cursor wait !important - opacity 0.7 + &.init + cursor wait !important + opacity 0.7 - &.init - cursor wait !important - opacity 0.7 + > i + margin-right 4px - > i - margin-right 4px + </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> diff --git a/src/web/app/mobile/tags/home-timeline.tag b/src/web/app/mobile/tags/home-timeline.tag index 1754bb2b07..6ad7270cef 100644 --- a/src/web/app/mobile/tags/home-timeline.tag +++ b/src/web/app/mobile/tags/home-timeline.tag @@ -1,40 +1,43 @@ -mk-home-timeline - mk-timeline@timeline(init={ init }, more={ more }, empty={ '表示する投稿がありません。誰かしらをフォローするなどしましょう。' }) +<mk-home-timeline> + <mk-timeline ref="timeline" init="{ init }" more="{ more }" empty="{ '表示する投稿がありません。誰かしらをフォローするなどしましょう。' }"></mk-timeline> + <style type="stylus"> + :scope + display block -style. - display block + </style> + <script> + @mixin \api + @mixin \stream -script. - @mixin \api - @mixin \stream + @init = new Promise (res, rej) ~> + @api \posts/timeline + .then (posts) ~> + res posts + @trigger \loaded - @init = new Promise (res, rej) ~> - @api \posts/timeline - .then (posts) ~> - res posts - @trigger \loaded + @on \mount ~> + @stream.on \post @on-stream-post + @stream.on \follow @on-stream-follow + @stream.on \unfollow @on-stream-unfollow - @on \mount ~> - @stream.on \post @on-stream-post - @stream.on \follow @on-stream-follow - @stream.on \unfollow @on-stream-unfollow + @on \unmount ~> + @stream.off \post @on-stream-post + @stream.off \follow @on-stream-follow + @stream.off \unfollow @on-stream-unfollow - @on \unmount ~> - @stream.off \post @on-stream-post - @stream.off \follow @on-stream-follow - @stream.off \unfollow @on-stream-unfollow + @more = ~> + @api \posts/timeline do + max_id: @refs.timeline.tail!.id - @more = ~> - @api \posts/timeline do - max_id: @refs.timeline.tail!.id + @on-stream-post = (post) ~> + @is-empty = false + @update! + @refs.timeline.add-post post - @on-stream-post = (post) ~> - @is-empty = false - @update! - @refs.timeline.add-post post + @on-stream-follow = ~> + @fetch! - @on-stream-follow = ~> - @fetch! - - @on-stream-unfollow = ~> - @fetch! + @on-stream-unfollow = ~> + @fetch! + </script> +</mk-home-timeline> diff --git a/src/web/app/mobile/tags/home.tag b/src/web/app/mobile/tags/home.tag index ebcf8f0bb2..e34d678126 100644 --- a/src/web/app/mobile/tags/home.tag +++ b/src/web/app/mobile/tags/home.tag @@ -1,17 +1,20 @@ -mk-home - mk-home-timeline@tl +<mk-home> + <mk-home-timeline ref="tl"></mk-home-timeline> + <style type="stylus"> + :scope + display block -style. - display block + > mk-home-timeline + max-width 600px + margin 0 auto - > mk-home-timeline - max-width 600px - margin 0 auto + @media (min-width 500px) + padding 16px - @media (min-width 500px) - padding 16px - -script. - @on \mount ~> - @refs.tl.on \loaded ~> - @trigger \loaded + </style> + <script> + @on \mount ~> + @refs.tl.on \loaded ~> + @trigger \loaded + </script> +</mk-home> diff --git a/src/web/app/mobile/tags/images-viewer.tag b/src/web/app/mobile/tags/images-viewer.tag index f9d774a124..12bb8e345d 100644 --- a/src/web/app/mobile/tags/images-viewer.tag +++ b/src/web/app/mobile/tags/images-viewer.tag @@ -1,25 +1,27 @@ -mk-images-viewer - div.image@view(onclick={ click }) - img@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 - - > img +<mk-images-viewer> + <div class="image" ref="view" onclick="{ click }"><img ref="img" src="{ image.url + '?thumbnail&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 -script. - @images = @opts.images - @image = @images.0 + > .image - @click = ~> - window.open @image.url + > img + display block + max-height 256px + max-width 100% + margin 0 auto + + </style> + <script> + @images = @opts.images + @image = @images.0 + + @click = ~> + window.open @image.url + </script> +</mk-images-viewer> diff --git a/src/web/app/mobile/tags/notification-preview.tag b/src/web/app/mobile/tags/notification-preview.tag index ee936df7ab..c6b7414a81 100644 --- a/src/web/app/mobile/tags/notification-preview.tag +++ b/src/web/app/mobile/tags/notification-preview.tag @@ -1,117 +1,109 @@ -mk-notification-preview(class={ notification.type }) - div.main(if={ notification.type == 'like' }) - img.avatar(src={ notification.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.text - p - i.fa.fa-thumbs-o-up - | { notification.user.name } - p.post-ref { get-post-summary(notification.post) } - - div.main(if={ notification.type == 'repost' }) - img.avatar(src={ notification.post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.text - p - i.fa.fa-retweet - | { notification.post.user.name } - p.post-ref { get-post-summary(notification.post.repost) } - - div.main(if={ notification.type == 'quote' }) - img.avatar(src={ notification.post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.text - p - i.fa.fa-quote-left - | { notification.post.user.name } - p.post-preview { get-post-summary(notification.post) } - - div.main(if={ notification.type == 'follow' }) - img.avatar(src={ notification.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.text - p - i.fa.fa-user-plus - | { notification.user.name } - - div.main(if={ notification.type == 'reply' }) - img.avatar(src={ notification.post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.text - p - i.fa.fa-reply - | { notification.post.user.name } - p.post-preview { get-post-summary(notification.post) } - - div.main(if={ notification.type == 'mention' }) - img.avatar(src={ notification.post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.text - p - i.fa.fa-at - | { notification.post.user.name } - p.post-preview { get-post-summary(notification.post) } - -style. - display block - margin 0 - padding 8px - color #fff - - > .main - word-wrap break-word - - &:after - content "" - display block - clear both - - img - display block - float left - 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 +<mk-notification-preview class="{ notification.type }"> + <div class="main" if="{ notification.type == 'like' }"><img class="avatar" src="{ notification.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/> + <div class="text"> + <p><i class="fa fa-thumbs-o-up"></i>{ notification.user.name }</p> + <p class="post-ref">{ getPostSummary(notification.post) }</p> + </div> + </div> + <div class="main" if="{ notification.type == 'repost' }"><img class="avatar" src="{ notification.post.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/> + <div class="text"> + <p><i class="fa fa-retweet"></i>{ notification.post.user.name }</p> + <p class="post-ref">{ getPostSummary(notification.post.repost) }</p> + </div> + </div> + <div class="main" if="{ notification.type == 'quote' }"><img class="avatar" src="{ notification.post.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/> + <div class="text"> + <p><i class="fa fa-quote-left"></i>{ notification.post.user.name }</p> + <p class="post-preview">{ getPostSummary(notification.post) }</p> + </div> + </div> + <div class="main" if="{ notification.type == 'follow' }"><img class="avatar" src="{ notification.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/> + <div class="text"> + <p><i class="fa fa-user-plus"></i>{ notification.user.name }</p> + </div> + </div> + <div class="main" if="{ notification.type == 'reply' }"><img class="avatar" src="{ notification.post.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/> + <div class="text"> + <p><i class="fa fa-reply"></i>{ notification.post.user.name }</p> + <p class="post-preview">{ getPostSummary(notification.post) }</p> + </div> + </div> + <div class="main" if="{ notification.type == 'mention' }"><img class="avatar" src="{ notification.post.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/> + <div class="text"> + <p><i class="fa fa-at"></i>{ notification.post.user.name }</p> + <p class="post-preview">{ getPostSummary(notification.post) }</p> + </div> + </div> + <style type="stylus"> + :scope + display block margin 0 - - i - margin-right 4px - - .post-ref - - &: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 + padding 8px color #fff -script. - @mixin \get-post-summary - @notification = @opts.notification + > .main + word-wrap break-word + + &:after + content "" + display block + clear both + + img + display block + float left + 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-ref + + &: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 #fff + + </style> + <script> + @mixin \get-post-summary + @notification = @opts.notification + </script> +</mk-notification-preview> diff --git a/src/web/app/mobile/tags/notification.tag b/src/web/app/mobile/tags/notification.tag index afcc7441b4..155ebf2930 100644 --- a/src/web/app/mobile/tags/notification.tag +++ b/src/web/app/mobile/tags/notification.tag @@ -1,142 +1,122 @@ -mk-notification(class={ notification.type }) - mk-time(time={ notification.created_at }) - - div.main(if={ notification.type == 'like' }) - a.avatar-anchor(href={ CONFIG.url + '/' + notification.user.username }) - img.avatar(src={ notification.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.text - p - i.fa.fa-thumbs-o-up - a(href={ CONFIG.url + '/' + notification.user.username }) { 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 }) - img.avatar(src={ notification.post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.text - p - i.fa.fa-retweet - a(href={ CONFIG.url + '/' + notification.post.user.username }) { 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 }) - img.avatar(src={ notification.post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.text - p - i.fa.fa-quote-left - a(href={ CONFIG.url + '/' + notification.post.user.username }) { 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 }) - img.avatar(src={ notification.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.text - p - i.fa.fa-user-plus - a(href={ CONFIG.url + '/' + notification.user.username }) { notification.user.name } - - div.main(if={ notification.type == 'reply' }) - a.avatar-anchor(href={ CONFIG.url + '/' + notification.post.user.username }) - img.avatar(src={ notification.post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.text - p - i.fa.fa-reply - a(href={ CONFIG.url + '/' + notification.post.user.username }) { 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 }) - img.avatar(src={ notification.post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.text - p - i.fa.fa-at - a(href={ CONFIG.url + '/' + notification.post.user.username }) { notification.post.user.name } - a.post-preview(href={ CONFIG.url + '/' + notification.post.user.username + '/' + notification.post.id }) { get-post-summary(notification.post) } - -style. - display block - margin 0 - padding 16px - - > mk-time - display inline - position absolute - top 16px - right 12px - vertical-align top - color rgba(0, 0, 0, 0.6) - font-size 12px - - > .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 +<mk-notification class="{ 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 }"><img class="avatar" src="{ notification.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/></a> + <div class="text"> + <p><i class="fa fa-thumbs-o-up"></i><a href="{ CONFIG.url + '/' + notification.user.username }">{ 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 }"><img class="avatar" src="{ notification.post.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/></a> + <div class="text"> + <p><i class="fa fa-retweet"></i><a href="{ CONFIG.url + '/' + notification.post.user.username }">{ 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 }"><img class="avatar" src="{ notification.post.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/></a> + <div class="text"> + <p><i class="fa fa-quote-left"></i><a href="{ CONFIG.url + '/' + notification.post.user.username }">{ 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 }"><img class="avatar" src="{ notification.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/></a> + <div class="text"> + <p><i class="fa fa-user-plus"></i><a href="{ CONFIG.url + '/' + notification.user.username }">{ 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 }"><img class="avatar" src="{ notification.post.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/></a> + <div class="text"> + <p><i class="fa fa-reply"></i><a href="{ CONFIG.url + '/' + notification.post.user.username }">{ 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 }"><img class="avatar" src="{ notification.post.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/></a> + <div class="text"> + <p><i class="fa fa-at"></i><a href="{ CONFIG.url + '/' + notification.post.user.username }">{ 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> + <style type="stylus"> + :scope + display block margin 0 + padding 16px - i - margin-right 4px + > mk-time + display inline + position absolute + top 16px + right 12px + vertical-align top + color rgba(0, 0, 0, 0.6) + font-size 12px - .post-preview - color rgba(0, 0, 0, 0.7) + > .main + word-wrap break-word - .post-ref - color rgba(0, 0, 0, 0.7) + &:after + content "" + display block + clear both - &:before, &:after - font-family FontAwesome - font-size 1em - font-weight normal - font-style normal - display inline-block - margin-right 3px + .avatar-anchor + display block + float left - &:before - content "\f10d" + img + min-width 36px + min-height 36px + max-width 36px + max-height 36px + border-radius 6px - &:after - content "\f10e" + .text + float right + width calc(100% - 36px) + padding-left 8px - &.like - .text p i - color #FFAC33 + p + margin 0 - &.repost, &.quote - .text p i - color #77B255 + i + margin-right 4px - &.follow - .text p i - color #53c7ce + .post-preview + color rgba(0, 0, 0, 0.7) - &.reply, &.mention - .text p i - color #555 + .post-ref + color rgba(0, 0, 0, 0.7) - .post-preview - 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 -script. - @mixin \get-post-summary - @notification = @opts.notification + &: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 + + .post-preview + color rgba(0, 0, 0, 0.7) + + </style> + <script> + @mixin \get-post-summary + @notification = @opts.notification + </script> +</mk-notification> diff --git a/src/web/app/mobile/tags/notifications.tag b/src/web/app/mobile/tags/notifications.tag index 7510d59967..9ebe1dc5c8 100644 --- a/src/web/app/mobile/tags/notifications.tag +++ b/src/web/app/mobile/tags/notifications.tag @@ -1,98 +1,93 @@ -mk-notifications - div.notifications(if={ notifications.length != 0 }) - virtual(each={ notification, i in notifications }) - mk-notification(notification={ notification }) - - 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 - background #fff - - > .notifications - margin 0 auto - max-width 500px - - > mk-notification - border-bottom solid 1px rgba(0, 0, 0, 0.05) - - &:last-child - border-bottom none - - > .date +<mk-notifications> + <div class="notifications" if="{ notifications.length != 0 }"> + <virtual each="{ notification, i in notifications }"> + <mk-notification notification="{ notification }"></mk-notification> + <p class="date" if="{ i != notifications.length - 1 && 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 && !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 - 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) + background #fff - span - margin 0 16px + > .notifications + margin 0 auto + max-width 500px - i - margin-right 8px + > mk-notification + border-bottom solid 1px rgba(0, 0, 0, 0.05) - > .empty - margin 0 - padding 16px - text-align center - color #aaa + &:last-child + border-bottom none - > .loading - margin 0 - padding 16px - text-align center - color #aaa + > .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) - > i - margin-right 4px + span + margin 0 16px -script. - @mixin \api - @mixin \stream - @mixin \get-post-summary + i + margin-right 8px - @notifications = [] - @loading = true + > .empty + margin 0 + padding 16px + text-align center + color #aaa - @on \mount ~> - @api \i/notifications - .then (notifications) ~> - @notifications = notifications - @loading = false + > .loading + margin 0 + padding 16px + text-align center + color #aaa + + > i + margin-right 4px + + </style> + <script> + @mixin \api + @mixin \stream + @mixin \get-post-summary + + @notifications = [] + @loading = true + + @on \mount ~> + @api \i/notifications + .then (notifications) ~> + @notifications = notifications + @loading = false + @update! + @trigger \loaded + .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! - @trigger \loaded - .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> diff --git a/src/web/app/mobile/tags/notify.tag b/src/web/app/mobile/tags/notify.tag index 9dd93ccf25..e50a1ef6c1 100644 --- a/src/web/app/mobile/tags/notify.tag +++ b/src/web/app/mobile/tags/notify.tag @@ -1,35 +1,38 @@ -mk-notify - mk-notification-preview(notification={ opts.notification }) +<mk-notify> + <mk-notification-preview notification="{ opts.notification }"></mk-notification-preview> + <style type="stylus"> + :scope + display block + position fixed + z-index 1024 + bottom -64px + left 0 + width 100% + height 64px + pointer-events none + -webkit-backdrop-filter blur(2px) + backdrop-filter blur(2px) + background-color rgba(#000, 0.5) -style. - display block - position fixed - z-index 1024 - bottom -64px - left 0 - width 100% - height 64px - pointer-events none - -webkit-backdrop-filter blur(2px) - backdrop-filter blur(2px) - background-color rgba(#000, 0.5) - -script. - @on \mount ~> - Velocity @root, { - bottom: \0px - } { - duration: 500ms - easing: \ease-out - } - - set-timeout ~> + </style> + <script> + @on \mount ~> Velocity @root, { - bottom: \-64px + bottom: \0px } { duration: 500ms easing: \ease-out - complete: ~> - @unmount! } - , 6000ms + + set-timeout ~> + Velocity @root, { + bottom: \-64px + } { + duration: 500ms + easing: \ease-out + complete: ~> + @unmount! + } + , 6000ms + </script> +</mk-notify> diff --git a/src/web/app/mobile/tags/page/drive.tag b/src/web/app/mobile/tags/page/drive.tag index 9bef7e6648..02287cecde 100644 --- a/src/web/app/mobile/tags/page/drive.tag +++ b/src/web/app/mobile/tags/page/drive.tag @@ -1,46 +1,51 @@ -mk-drive-page - mk-ui@ui: mk-drive@browser(folder={ parent.opts.folder }, file={ parent.opts.file }) +<mk-drive-page> + <mk-ui ref="ui"> + <mk-drive ref="browser" folder="{ parent.opts.folder }" file="{ parent.opts.file }"></mk-drive> + </mk-ui> + <style type="stylus"> + :scope + display block -style. - display block + </style> + <script> + @mixin \ui + @mixin \ui-progress -script. - @mixin \ui - @mixin \ui-progress - - @on \mount ~> - document.title = 'Misskey Drive' - @ui.trigger \title '<i class="fa fa-cloud"></i>ドライブ' - - @refs.ui.refs.browser.on \begin-load ~> - @Progress.start! - - @refs.ui.refs.browser.on \loaded-mid ~> - @Progress.set 0.5 - - @refs.ui.refs.browser.on \loaded ~> - @Progress.done! - - @refs.ui.refs.browser.on \move-root ~> + @on \mount ~> + document.title = 'Misskey Drive' @ui.trigger \title '<i class="fa fa-cloud"></i>ドライブ' - # Rewrite URL - history.push-state null null '/i/drive' + @refs.ui.refs.browser.on \begin-load ~> + @Progress.start! - @refs.ui.refs.browser.on \cd (folder) ~> - # TODO: escape html characters in folder.name - @ui.trigger \title '<i class="fa fa-folder-open"></i>' + folder.name + @refs.ui.refs.browser.on \loaded-mid ~> + @Progress.set 0.5 - @refs.ui.refs.browser.on \move (folder) ~> - # Rewrite URL - history.push-state null null '/i/drive/folder/' + folder.id + @refs.ui.refs.browser.on \loaded ~> + @Progress.done! - @refs.ui.refs.browser.on \open-file (file) ~> - # TODO: escape html characters in file.name - @ui.trigger \title '<mk-file-type-icon class="icon"></mk-file-type-icon>' + file.name + @refs.ui.refs.browser.on \move-root ~> + @ui.trigger \title '<i class="fa fa-cloud"></i>ドライブ' - # Rewrite URL - history.push-state null null '/i/drive/file/' + file.id + # Rewrite URL + history.push-state null null '/i/drive' - riot.mount \mk-file-type-icon do - file: file + @refs.ui.refs.browser.on \cd (folder) ~> + # TODO: escape html characters in folder.name + @ui.trigger \title '<i class="fa fa-folder-open"></i>' + folder.name + + @refs.ui.refs.browser.on \move (folder) ~> + # Rewrite URL + history.push-state null null '/i/drive/folder/' + folder.id + + @refs.ui.refs.browser.on \open-file (file) ~> + # TODO: escape html characters in file.name + @ui.trigger \title '<mk-file-type-icon class="icon"></mk-file-type-icon>' + file.name + + # Rewrite URL + history.push-state null null '/i/drive/file/' + file.id + + riot.mount \mk-file-type-icon do + file: file + </script> +</mk-drive-page> diff --git a/src/web/app/mobile/tags/page/entrance.tag b/src/web/app/mobile/tags/page/entrance.tag index 67d8bc9bbf..85910e8e89 100644 --- a/src/web/app/mobile/tags/page/entrance.tag +++ b/src/web/app/mobile/tags/page/entrance.tag @@ -1,57 +1,60 @@ -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 }) わかった - - footer - mk-copyright - -style. - display block - height 100% - - > main - display block - - > img +<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> + <footer> + <mk-copyright></mk-copyright> + </footer> + <style type="stylus"> + :scope display block - width 130px - height 120px - margin 0 auto + height 100% - > .introduction - max-width 300px - margin 0 auto - color #666 - - > button + > main display block - margin 16px auto 0 auto - > footer - > mk-copyright - margin 0 - text-align center - line-height 64px - font-size 10px - color rgba(#000, 0.5) + > img + display block + width 130px + height 120px + margin 0 auto -script. - @mode = \signin + > .introduction + max-width 300px + margin 0 auto + color #666 - @signup = ~> - @mode = \signup - @update! + > button + display block + margin 16px auto 0 auto - @signin = ~> + > 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> diff --git a/src/web/app/mobile/tags/page/entrance/signin.tag b/src/web/app/mobile/tags/page/entrance/signin.tag index 484c414e8e..0c5efe620f 100644 --- a/src/web/app/mobile/tags/page/entrance/signin.tag +++ b/src/web/app/mobile/tags/page/entrance/signin.tag @@ -1,45 +1,51 @@ -mk-entrance-signin - mk-signin - div.divider: span or - button.signup(onclick={ parent.signup }) 新規登録 - a.introduction(onclick={ parent.introduction }) Misskeyについて - -style. - display block - margin 0 auto - padding 0 8px - max-width 350px - text-align center - - > .signup - padding 16px - width 100% - font-size 1em - color #fff - background $theme-color - border-radius 3px - - > .divider - padding 16px 0 - text-align center - - &:after - content "" +<mk-entrance-signin> + <mk-signin></mk-signin> + <div class="divider"><span>or</span></div> + <button class="signup" onclick="{ parent.signup }">新規登録</button><a class="introduction" onclick="{ parent.introduction }">Misskeyについて</a> + <style type="stylus"> + :scope display block - position absolute - top 50% - width 100% - height 1px - border-top solid 1px rgba(0, 0, 0, 0.1) - - > * - z-index 1 + margin 0 auto padding 0 8px - color rgba(0, 0, 0, 0.5) - background #fdfdfd + max-width 350px + text-align center - > .introduction - display inline-block - margin-top 16px - font-size 12px - color #666 + > .signup + padding 16px + width 100% + font-size 1em + color #fff + background $theme-color + border-radius 3px + + > .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 + + > .introduction + display inline-block + margin-top 16px + font-size 12px + color #666 + + + + + + </style> +</mk-entrance-signin> diff --git a/src/web/app/mobile/tags/page/entrance/signup.tag b/src/web/app/mobile/tags/page/entrance/signup.tag index a28f85e634..77dff97511 100644 --- a/src/web/app/mobile/tags/page/entrance/signup.tag +++ b/src/web/app/mobile/tags/page/entrance/signup.tag @@ -1,35 +1,42 @@ -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 + margin 0 auto + padding 0 8px + max-width 350px -style. - display block - margin 0 auto - padding 0 8px - max-width 350px + > .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 + 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 - 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> diff --git a/src/web/app/mobile/tags/page/home.tag b/src/web/app/mobile/tags/page/home.tag index c8d7729652..eb53be6601 100644 --- a/src/web/app/mobile/tags/page/home.tag +++ b/src/web/app/mobile/tags/page/home.tag @@ -1,40 +1,45 @@ -mk-home-page - mk-ui@ui: mk-home@home +<mk-home-page> + <mk-ui ref="ui"> + <mk-home ref="home"></mk-home> + </mk-ui> + <style type="stylus"> + :scope + display block -style. - display block + </style> + <script> + @mixin \i + @mixin \ui + @mixin \ui-progress + @mixin \stream + @mixin \get-post-summary -script. - @mixin \i - @mixin \ui - @mixin \ui-progress - @mixin \stream - @mixin \get-post-summary + @unread-count = 0 - @unread-count = 0 - - @on \mount ~> - document.title = 'Misskey' - @ui.trigger \title '<i class="fa fa-home"></i>ホーム' - - @Progress.start! - - @stream.on \post @on-stream-post - document.add-event-listener \visibilitychange @window-on-visibilitychange, false - - @refs.ui.refs.home.on \loaded ~> - @Progress.done! - - @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 + @on \mount ~> document.title = 'Misskey' + @ui.trigger \title '<i class="fa fa-home"></i>ホーム' + + @Progress.start! + + @stream.on \post @on-stream-post + document.add-event-listener \visibilitychange @window-on-visibilitychange, false + + @refs.ui.refs.home.on \loaded ~> + @Progress.done! + + @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> diff --git a/src/web/app/mobile/tags/page/new-post.tag b/src/web/app/mobile/tags/page/new-post.tag index 21e00fc1f9..1b6f73875c 100644 --- a/src/web/app/mobile/tags/page/new-post.tag +++ b/src/web/app/mobile/tags/page/new-post.tag @@ -1,5 +1,12 @@ -mk-new-post-page - mk-post-form@form +<mk-new-post-page> + <mk-post-form ref="form"></mk-post-form> + <style type="stylus"> + :scope + display block -style. - display block + + + + + </style> +</mk-new-post-page> diff --git a/src/web/app/mobile/tags/page/notifications.tag b/src/web/app/mobile/tags/page/notifications.tag index 9fb34dcd75..666a076cb2 100644 --- a/src/web/app/mobile/tags/page/notifications.tag +++ b/src/web/app/mobile/tags/page/notifications.tag @@ -1,18 +1,23 @@ -mk-notifications-page - mk-ui@ui: mk-notifications@notifications +<mk-notifications-page> + <mk-ui ref="ui"> + <mk-notifications ref="notifications"></mk-notifications> + </mk-ui> + <style type="stylus"> + :scope + display block -style. - display block + </style> + <script> + @mixin \ui + @mixin \ui-progress -script. - @mixin \ui - @mixin \ui-progress + @on \mount ~> + document.title = 'Misskey | 通知' + @ui.trigger \title '<i class="fa fa-bell-o"></i>通知' - @on \mount ~> - document.title = 'Misskey | 通知' - @ui.trigger \title '<i class="fa fa-bell-o"></i>通知' + @Progress.start! - @Progress.start! - - @refs.ui.refs.notifications.on \loaded ~> - @Progress.done! + @refs.ui.refs.notifications.on \loaded ~> + @Progress.done! + </script> +</mk-notifications-page> diff --git a/src/web/app/mobile/tags/page/post.tag b/src/web/app/mobile/tags/page/post.tag index 1dc74d267a..40ba429ec4 100644 --- a/src/web/app/mobile/tags/page/post.tag +++ b/src/web/app/mobile/tags/page/post.tag @@ -1,31 +1,38 @@ -mk-post-page - mk-ui@ui: main: mk-post-detail@post(post={ parent.post }) +<mk-post-page> + <mk-ui ref="ui"> + <main> + <mk-post-detail ref="post" post="{ parent.post }"></mk-post-detail> + </main> + </mk-ui> + <style type="stylus"> + :scope + display block -style. - display block + main + background #fff - main - background #fff + > mk-post-detail + width 100% + max-width 500px + margin 0 auto - > mk-post-detail - width 100% - max-width 500px - margin 0 auto + </style> + <script> + @mixin \ui + @mixin \ui-progress -script. - @mixin \ui - @mixin \ui-progress + @post = @opts.post - @post = @opts.post + @on \mount ~> + document.title = 'Misskey' + @ui.trigger \title '<i class="fa fa-sticky-note-o"></i>投稿' - @on \mount ~> - document.title = 'Misskey' - @ui.trigger \title '<i class="fa fa-sticky-note-o"></i>投稿' + @Progress.start! - @Progress.start! + @refs.ui.refs.post.on \post-fetched ~> + @Progress.set 0.5 - @refs.ui.refs.post.on \post-fetched ~> - @Progress.set 0.5 - - @refs.ui.refs.post.on \loaded ~> - @Progress.done! + @refs.ui.refs.post.on \loaded ~> + @Progress.done! + </script> +</mk-post-page> diff --git a/src/web/app/mobile/tags/page/search.tag b/src/web/app/mobile/tags/page/search.tag index 20de271f73..9dd1d4e92a 100644 --- a/src/web/app/mobile/tags/page/search.tag +++ b/src/web/app/mobile/tags/page/search.tag @@ -1,19 +1,24 @@ -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 + @mixin \ui-progress -script. - @mixin \ui - @mixin \ui-progress + @on \mount ~> + document.title = '検索: ' + @opts.query + ' | Misskey' + # TODO: クエリをHTMLエスケープ + @ui.trigger \title '<i class="fa fa-search"></i>' + @opts.query - @on \mount ~> - document.title = '検索: ' + @opts.query + ' | Misskey' - # TODO: クエリをHTMLエスケープ - @ui.trigger \title '<i class="fa fa-search"></i>' + @opts.query + @Progress.start! - @Progress.start! - - @refs.ui.refs.search.on \loaded ~> - @Progress.done! + @refs.ui.refs.search.on \loaded ~> + @Progress.done! + </script> +</mk-search-page> diff --git a/src/web/app/mobile/tags/page/user-followers.tag b/src/web/app/mobile/tags/page/user-followers.tag index e7e9a6fd1e..9809f7085f 100644 --- a/src/web/app/mobile/tags/page/user-followers.tag +++ b/src/web/app/mobile/tags/page/user-followers.tag @@ -1,31 +1,36 @@ -mk-user-followers-page - mk-ui@ui: mk-user-followers@list(if={ !parent.fetching }, user={ parent.user }) +<mk-user-followers-page> + <mk-ui ref="ui"> + <mk-user-followers ref="list" if="{ !parent.fetching }" user="{ parent.user }"></mk-user-followers> + </mk-ui> + <style type="stylus"> + :scope + display block -style. - display block + </style> + <script> + @mixin \ui + @mixin \ui-progress + @mixin \api -script. - @mixin \ui - @mixin \ui-progress - @mixin \api + @fetching = true + @user = null - @fetching = true - @user = null + @on \mount ~> + @Progress.start! - @on \mount ~> - @Progress.start! + @api \users/show do + username: @opts.user + .then (user) ~> + @user = user + @fetching = false - @api \users/show do - username: @opts.user - .then (user) ~> - @user = user - @fetching = false + document.title = user.name + 'のフォロワー | Misskey' + # TODO: ユーザー名をエスケープ + @ui.trigger \title '<img src="' + user.avatar_url + '?thumbnail&size=64">' + user.name + 'のフォロー' - document.title = user.name + 'のフォロワー | Misskey' - # TODO: ユーザー名をエスケープ - @ui.trigger \title '<img src="' + user.avatar_url + '?thumbnail&size=64">' + user.name + 'のフォロー' + @update! - @update! - - @refs.ui.refs.list.on \loaded ~> - @Progress.done! + @refs.ui.refs.list.on \loaded ~> + @Progress.done! + </script> +</mk-user-followers-page> diff --git a/src/web/app/mobile/tags/page/user-following.tag b/src/web/app/mobile/tags/page/user-following.tag index a74ba97b72..71070eb0da 100644 --- a/src/web/app/mobile/tags/page/user-following.tag +++ b/src/web/app/mobile/tags/page/user-following.tag @@ -1,31 +1,36 @@ -mk-user-following-page - mk-ui@ui: mk-user-following@list(if={ !parent.fetching }, user={ parent.user }) +<mk-user-following-page> + <mk-ui ref="ui"> + <mk-user-following ref="list" if="{ !parent.fetching }" user="{ parent.user }"></mk-user-following> + </mk-ui> + <style type="stylus"> + :scope + display block -style. - display block + </style> + <script> + @mixin \ui + @mixin \ui-progress + @mixin \api -script. - @mixin \ui - @mixin \ui-progress - @mixin \api + @fetching = true + @user = null - @fetching = true - @user = null + @on \mount ~> + @Progress.start! - @on \mount ~> - @Progress.start! + @api \users/show do + username: @opts.user + .then (user) ~> + @user = user + @fetching = false - @api \users/show do - username: @opts.user - .then (user) ~> - @user = user - @fetching = false + document.title = user.name + 'のフォロー | Misskey' + # TODO: ユーザー名をエスケープ + @ui.trigger \title '<img src="' + user.avatar_url + '?thumbnail&size=64">' + user.name + 'のフォロー' - document.title = user.name + 'のフォロー | Misskey' - # TODO: ユーザー名をエスケープ - @ui.trigger \title '<img src="' + user.avatar_url + '?thumbnail&size=64">' + user.name + 'のフォロー' + @update! - @update! - - @refs.ui.refs.list.on \loaded ~> - @Progress.done! + @refs.ui.refs.list.on \loaded ~> + @Progress.done! + </script> +</mk-user-following-page> diff --git a/src/web/app/mobile/tags/page/user.tag b/src/web/app/mobile/tags/page/user.tag index 9667abfd14..f6106c95cc 100644 --- a/src/web/app/mobile/tags/page/user.tag +++ b/src/web/app/mobile/tags/page/user.tag @@ -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 + @mixin \ui-progress -script. - @mixin \ui - @mixin \ui-progress + @user = @opts.user - @user = @opts.user + @on \mount ~> + @Progress.start! - @on \mount ~> - @Progress.start! - - @refs.ui.refs.user.on \loaded (user) ~> - @Progress.done! - document.title = user.name + ' | Misskey' - # TODO: ユーザー名をエスケープ - @ui.trigger \title '<i class="fa fa-user"></i>' + user.name + @refs.ui.refs.user.on \loaded (user) ~> + @Progress.done! + document.title = user.name + ' | Misskey' + # TODO: ユーザー名をエスケープ + @ui.trigger \title '<i class="fa fa-user"></i>' + user.name + </script> +</mk-user-page> diff --git a/src/web/app/mobile/tags/post-detail.tag b/src/web/app/mobile/tags/post-detail.tag index c7eb091ce6..b8d8ec3d8d 100644 --- a/src/web/app/mobile/tags/post-detail.tag +++ b/src/web/app/mobile/tags/post-detail.tag @@ -1,415 +1,409 @@ -mk-post-detail - - 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 }, 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-preview(post={ post }) - - div.reply-to(if={ p.reply_to }) - mk-post-preview(post={ p.reply_to }) - - div.repost(if={ is-repost }) - p - a.avatar-anchor(href={ CONFIG.url + '/' + post.user.username }): 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') - header - a.name(href={ CONFIG.url + '/' + p.user.username }) - | { p.user.name } - span.username - | @{ p.user.username } - 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 }) - a.time(href={ url }) - mk-time(time={ p.created_at }, mode='detail') - 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 }) - 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 }) - 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 - - > .fetching - padding 64px 0 - - > .main - - > .read-more +<mk-post-detail> + <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 && p.reply_to.reply_to_id && context == null }" 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-preview post="{ post }"></mk-post-preview> + </virtual> + </div> + <div class="reply-to" if="{ p.reply_to }"> + <mk-post-preview post="{ p.reply_to }"></mk-post-preview> + </div> + <div class="repost" if="{ isRepost }"> + <p><a class="avatar-anchor" href="{ CONFIG.url + '/' + post.user.username }"><img class="avatar" src="{ post.user.avatar_url + '?thumbnail&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&size=64' }" alt="avatar"/></a> + <header><a class="name" href="{ CONFIG.url + '/' + p.user.username }">{ p.user.name }</a><span class="username">@{ p.user.username }</span></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&size=512' }" alt="{ file.name }" title="{ file.name }"/></virtual> + </div> + </div><a class="time" href="{ url }"> + <mk-time time="{ p.created_at }" mode="detail"></mk-time></a> + <footer> + <button onclick="{ reply }" title="返信"><i class="fa fa-reply"></i> + <p class="count" if="{ p.replies_count > 0 }">{ p.replies_count }</p> + </button> + <button onclick="{ repost }" title="Repost"><i class="fa fa-retweet"></i> + <p class="count" if="{ p.repost_count > 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 > 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 && reposts.length > 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 }"><img class="avatar" src="{ user.avatar_url + '?thumbnail&size=32' }" alt=""/></a></li> + </ol> + </div> + <div class="likes" if="{ likes && likes.length > 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 }"><img class="avatar" src="{ avatar_url + '?thumbnail&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 - box-shadow none + padding 0 - &: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 14px 16px 9px 16px - - @media (min-width 500px) - padding 28px 32px 18px 32px - - &:after - content "" - display block - clear both - - &:hover - > .main > footer > button - color #888 - - > .avatar-anchor - display block - - > .avatar - display block - width 54px - height 54px - margin 0 - border-radius 8px - vertical-align bottom - - @media (min-width 500px) - width 60px - height 60px - - > header - position absolute - top 18px - left 80px - width calc(100% - 80px) - - @media (min-width 500px) - top 28px - left 108px - width calc(100% - 108px) - - > .name - display inline-block - margin 0 - color #777 - font-size 16px - font-weight bold - text-align left - text-decoration none - - &:hover - text-decoration underline - - > .username - display block - text-align left - margin 0 - color #ccc - - > .body - padding 8px 0 - - > .text - cursor default + > .read-more display block margin 0 - padding 0 - word-wrap break-word - font-size 16px - color #717171 - - @media (min-width 500px) - font-size 24px - - > mk-url-preview - margin-top 8px - - > .media - > img - display block - max-width 100% - - > .time - font-size 16px - color #c0c0c0 - - > footer - font-size 1.2em - - > button - margin 0 28px 0 0 - padding 8px - background transparent - border none - box-shadow none + padding 10px 0 + width 100% 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 + box-shadow none &: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 14px 16px 9px 16px + + @media (min-width 500px) + padding 28px 32px 18px 32px + + &:after + content "" + display block + clear both + + &:hover + > .main > footer > button + color #888 + + > .avatar-anchor + display block + + > .avatar + display block + width 54px + height 54px + margin 0 + border-radius 8px + vertical-align bottom + + @media (min-width 500px) + width 60px + height 60px > header - flex 1 1 80px - max-width 80px - padding 8px 5px 0px 10px + position absolute + top 18px + left 80px + width calc(100% - 80px) - > a + @media (min-width 500px) + top 28px + left 108px + width calc(100% - 108px) + + > .name + display inline-block + margin 0 + color #777 + font-size 16px + font-weight bold + 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 + > .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 16px + color #717171 - > .avatar-anchor - display:block + @media (min-width 500px) + font-size 24px - > .avatar - vertical-align bottom - width 24px - height 24px - border-radius 4px + > mk-url-preview + margin-top 8px - > .reposts + .likes - margin-left 16px + > .media + > img + display block + max-width 100% - > .replies - > * - border-top 1px solid #eef0f2 + > .time + font-size 16px + color #c0c0c0 -script. - @mixin \api - @mixin \text - @mixin \get-post-summary - @mixin \open-post-form + > footer + font-size 1.2em - @fetching = true - @loading-context = false - @content = null - @post = null + > button + margin 0 28px 0 0 + padding 8px + background transparent + border none + box-shadow none + font-size 1em + color #ddd + cursor pointer - @on \mount ~> - @api \posts/show do - post_id: @opts.post - .then (post) ~> - @post = post - @is-repost = @post.repost? - @p = if @is-repost then @post.repost else @post - @summary = @get-post-summary @p - @trigger \loaded - @fetching = false - @update! + &:hover + color #666 - if @p.text? - tokens = @analyze @p.text - @refs.text.innerHTML = @compile tokens + > .count + display inline + margin 0 0 0 8px + color #999 - @refs.text.children.for-each (e) ~> - if e.tag-name == \MK-URL - riot.mount e + &.liked + color $theme-color - # 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 + > .reposts-and-likes + display flex + justify-content center + padding 0 + margin 16px 0 - # Get likes - @api \posts/likes do - post_id: @p.id - limit: 8 - .then (likes) ~> - @likes = likes + &:empty + display none + + > .reposts + > .likes + display flex + flex 1 1 + padding 0 + border-top solid 1px #F2EFEE + + > header + flex 1 1 80px + max-width 80px + padding 8px 5px 0px 10px + + > a + display block + font-size 1.5em + line-height 1.4em + + > p + 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 + + > .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 \get-post-summary + @mixin \open-post-form + + @fetching = true + @loading-context = false + @content = null + @post = null + + @on \mount ~> + @api \posts/show do + post_id: @opts.post + .then (post) ~> + @post = post + @is-repost = @post.repost? + @p = if @is-repost then @post.repost else @post + @summary = @get-post-summary @p + @trigger \loaded + @fetching = false @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! + + @reply = ~> + @open-post-form do + reply: @p + + @repost = ~> + text = window.prompt '「' + @summary + '」をRepost' + if text? + @api \posts/create do + repost_id: @p.id + text: if text == '' then undefined else text + + @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! - - # Get replies - @api \posts/replies do - post_id: @p.id - limit: 8 - .then (replies) ~> - @replies = replies - @update! - - @reply = ~> - @open-post-form do - reply: @p - - @repost = ~> - text = window.prompt '「' + @summary + '」をRepost' - if text? - @api \posts/create do - repost_id: @p.id - text: if text == '' then undefined else text - - @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> diff --git a/src/web/app/mobile/tags/post-form.tag b/src/web/app/mobile/tags/post-form.tag index 759a0820b8..838de1fc48 100644 --- a/src/web/app/mobile/tags/post-form.tag +++ b/src/web/app/mobile/tags/post-form.tag @@ -1,254 +1,264 @@ -mk-post-form - header: div - button.cancel(onclick={ cancel }): i.fa.fa-times - div - span.text-count(class={ over: refs.text.value.length > 300 }) { 300 - refs.text.value.length } - button.submit(onclick={ post }) 投稿 - div.form - mk-post-preview(if={ opts.reply }, post={ opts.reply }) - textarea@text(disabled={ wait }, oninput={ update }, onkeypress={ onkeypress }, 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 }) - li.add(if={ files.length < 4 }, title='PCからファイルを添付', onclick={ select-file }): i.fa.fa-plus - mk-uploader@uploader - button@upload(onclick={ select-file }): i.fa.fa-upload - button@drive(onclick={ select-file-from-drive }): i.fa.fa-cloud - input@file(type='file', accept='image/*', multiple, onchange={ change-file }) +<mk-post-form> + <header> + <div> + <button class="cancel" onclick="{ cancel }"><i class="fa fa-times"></i></button> + <div><span class="text-count { over: refs.text.value.length > 300 }">{ 300 - refs.text.value.length }</span> + <button class="submit" onclick="{ post }">投稿</button> + </div> + </div> + </header> + <div class="form"> + <mk-post-preview if="{ opts.reply }" post="{ opts.reply }"></mk-post-preview> + <textarea ref="text" disabled="{ wait }" oninput="{ update }" onkeypress="{ onkeypress }" 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 + "?thumbnail&size=64" })" title="{ name }"></div> + </li> + <li class="add" if="{ files.length < 4 }" title="PCからファイルを添付" onclick="{ selectFile }"><i class="fa fa-plus"></i></li> + </ul> + </div> + <mk-uploader ref="uploader"></mk-uploader> + <button ref="upload" onclick="{ selectFile }"><i class="fa fa-upload"></i></button> + <button ref="drive" onclick="{ selectFileFromDrive }"><i class="fa fa-cloud"></i></button> + <input ref="file" type="file" accept="image/*" multiple="multiple" onchange="{ changeFile }"/> + </div> + <style type="stylus"> + :scope + display block + padding-top 50px -style. - display block - padding-top 50px - - > header - position fixed - z-index 1000 - top 0 - left 0 - width 100% - height 50px - background #fff - - > div - max-width 500px - margin 0 auto - - > .cancel - width 50px - line-height 50px - font-size 24px - color #555 - - > div - position absolute + > header + position fixed + z-index 1000 top 0 - right 0 + left 0 + width 100% + height 50px + background #fff - > .text-count - line-height 50px - color #657786 + > div + max-width 500px + margin 0 auto - > .submit - margin 8px - padding 0 16px - line-height 34px - color $theme-color-foreground - background $theme-color - border-radius 4px + > .cancel + width 50px + line-height 50px + font-size 24px + color #555 + + > div + position absolute + top 0 + right 0 + + > .text-count + line-height 50px + color #657786 + + > .submit + margin 8px + padding 0 16px + line-height 34px + color $theme-color-foreground + background $theme-color + border-radius 4px + + &:disabled + opacity 0.7 + + > .form + max-width 500px + margin 0 auto + + > mk-post-preview + padding 16px + + > .attaches + + > .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 + + > [ref='file'] + display none + + > [ref='text'] + display block + padding 12px + margin 0 + width 100% + max-width 100% + min-width 100% + min-height 80px + font-size 16px + color #333 + border none + border-bottom solid 1px #ddd + border-radius 0 &:disabled - opacity 0.7 + opacity 0.5 - > .form - max-width 500px - margin 0 auto - - > mk-post-preview - padding 16px - - > .attaches - - > .files - display block - margin 0 - padding 4px - list-style none - - &:after - content "" - display block - clear both - - > .file - display block - float left - margin 4px + > [ref='upload'] + > [ref='drive'] + display inline-block padding 0 - cursor move + margin 0 + width 48px + height 48px + font-size 20px + color #657786 + background transparent + outline none + border none + border-radius 0 + box-shadow none - &:hover > .remove - display block + </style> + <script> + @mixin \api - > .img - width 64px - height 64px - background-size cover - background-position center center + @wait = false + @uploadings = [] + @files = [] - > .remove - display none - position absolute - top -6px - right -6px - width 16px - height 16px - cursor pointer + @on \mount ~> + @refs.uploader.on \uploaded (file) ~> + @add-file file - > .add - display block - float left - margin 4px - padding 0 - border dashed 2px rgba($theme-color, 0.2) - cursor pointer + @refs.uploader.on \change-uploads (uploads) ~> + @trigger \change-uploading-files uploads - &:hover - border-color rgba($theme-color, 0.3) + @refs.text.focus! - > i - color rgba($theme-color, 0.4) + @onkeypress = (e) ~> + if (e.char-code == 10 || e.char-code == 13) && e.ctrl-key + @post! + else + return true - > 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 - - > [ref='file'] - display none - - > [ref='text'] - display block - padding 12px - margin 0 - width 100% - max-width 100% - min-width 100% - min-height 80px - font-size 16px - color #333 - border none - border-bottom solid 1px #ddd - border-radius 0 - - &:disabled - opacity 0.5 - - > [ref='upload'] - > [ref='drive'] - display inline-block - padding 0 - margin 0 - width 48px - height 48px - font-size 20px - color #657786 - background transparent - outline none - border none - border-radius 0 - box-shadow none - -script. - @mixin \api - - @wait = false - @uploadings = [] - @files = [] - - @on \mount ~> - @refs.uploader.on \uploaded (file) ~> - @add-file file - - @refs.uploader.on \change-uploads (uploads) ~> - @trigger \change-uploading-files uploads - - @refs.text.focus! - - @onkeypress = (e) ~> - if (e.char-code == 10 || e.char-code == 13) && e.ctrl-key - @post! - else + @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! return true - @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! - return true + @select-file = ~> + @refs.file.click! - @select-file = ~> - @refs.file.click! + @select-file-from-drive = ~> + browser = document.body.append-child document.create-element \mk-drive-selector + browser = riot.mount browser, do + multiple: true + .0 + browser.on \selected (files) ~> + files.for-each @add-file - @select-file-from-drive = ~> - browser = document.body.append-child document.create-element \mk-drive-selector - browser = riot.mount browser, do - multiple: true - .0 - browser.on \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 - @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 - @upload = (file) ~> - @refs.uploader.upload file + @add-file = (file) ~> + file._remove = ~> + @files = @files.filter (x) -> x.id != file.id + @trigger \change-files @files + @update! - @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! + @post = ~> + @wait = true - @post = ~> - @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 @opts.reply? then @opts.reply.id else undefined + .then (data) ~> + @trigger \post + @unmount! + .catch (err) ~> + console.error err + #@opts.ui.trigger \notification 'Error!' + @wait = false + @update! - @api \posts/create do - text: @refs.text.value - media_ids: files - reply_to_id: if @opts.reply? then @opts.reply.id else undefined - .then (data) ~> - @trigger \post + @cancel = ~> + @trigger \cancel @unmount! - .catch (err) ~> - console.error err - #@opts.ui.trigger \notification 'Error!' - @wait = false - @update! - - @cancel = ~> - @trigger \cancel - @unmount! + </script> +</mk-post-form> diff --git a/src/web/app/mobile/tags/post-preview.tag b/src/web/app/mobile/tags/post-preview.tag index e15b2be244..71faab2b85 100644 --- a/src/web/app/mobile/tags/post-preview.tag +++ b/src/web/app/mobile/tags/post-preview.tag @@ -1,89 +1,86 @@ -mk-post-preview - article - a.avatar-anchor(href={ CONFIG.url + '/' + post.user.username }) - img.avatar(src={ post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.main - header - a.name(href={ CONFIG.url + '/' + post.user.username }) - | { 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> + <article><a class="avatar-anchor" href="{ CONFIG.url + '/' + post.user.username }"><img class="avatar" src="{ post.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/></a> + <div class="main"> + <header><a class="name" href="{ CONFIG.url + '/' + post.user.username }">{ 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 12px 0 0 + &:after + content "" + display block + clear both - > .avatar - display block - width 48px - height 48px - margin 0 - border-radius 8px - vertical-align bottom + &:hover + > .main > footer > button + color #888 - > .main - float left - width calc(100% - 60px) + > .avatar-anchor + display block + float left + margin 0 12px 0 0 - > header - margin-bottom 4px - white-space nowrap + > .avatar + display block + width 48px + height 48px + 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% - 60px) - &: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. - @post = @opts.post + > .body + + > .text + cursor default + margin 0 + padding 0 + font-size 1.1em + color #717171 + + </style> + <script>@post = @opts.post</script> +</mk-post-preview> diff --git a/src/web/app/mobile/tags/search-posts.tag b/src/web/app/mobile/tags/search-posts.tag index 4b1b12af27..c22d794b5b 100644 --- a/src/web/app/mobile/tags/search-posts.tag +++ b/src/web/app/mobile/tags/search-posts.tag @@ -1,29 +1,32 @@ -mk-search-posts - mk-timeline(init={ init }, more={ more }, empty={ '「' + query + '」に関する投稿は見つかりませんでした。' }) +<mk-search-posts> + <mk-timeline init="{ init }" more="{ more }" empty="{ '「' + query + '」に関する投稿は見つかりませんでした。' }"></mk-timeline> + <style type="stylus"> + :scope + display block + background #fff -style. - display block - background #fff + </style> + <script> + @mixin \api -script. - @mixin \api + @max = 30 + @offset = 0 - @max = 30 - @offset = 0 + @query = @opts.query + @with-media = @opts.with-media - @query = @opts.query - @with-media = @opts.with-media + @init = new Promise (res, rej) ~> + @api \posts/search do + query: @query + .then (posts) ~> + res posts + @trigger \loaded - @init = new Promise (res, rej) ~> - @api \posts/search do - query: @query - .then (posts) ~> - res posts - @trigger \loaded - - @more = ~> - @offset += @max - @api \posts/search do - query: @query - max: @max - offset: @offset + @more = ~> + @offset += @max + @api \posts/search do + query: @query + max: @max + offset: @offset + </script> +</mk-search-posts> diff --git a/src/web/app/mobile/tags/search.tag b/src/web/app/mobile/tags/search.tag index bf2299cc9b..bb0744147f 100644 --- a/src/web/app/mobile/tags/search.tag +++ b/src/web/app/mobile/tags/search.tag @@ -1,12 +1,15 @@ -mk-search - mk-search-posts@posts(query={ query }) +<mk-search> + <mk-search-posts ref="posts" query="{ query }"></mk-search-posts> + <style type="stylus"> + :scope + display block -style. - display block + </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> diff --git a/src/web/app/mobile/tags/stream-indicator.tag b/src/web/app/mobile/tags/stream-indicator.tag index 2eb5889ca6..4046f5fec4 100644 --- a/src/web/app/mobile/tags/stream-indicator.tag +++ b/src/web/app/mobile/tags/stream-indicator.tag @@ -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> diff --git a/src/web/app/mobile/tags/sub-post-content.tag b/src/web/app/mobile/tags/sub-post-content.tag index 595f63d794..0f015fddfd 100644 --- a/src/web/app/mobile/tags/sub-post-content.tag +++ b/src/web/app/mobile/tags/sub-post-content.tag @@ -1,36 +1,37 @@ -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 -script. - @mixin \text + @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> diff --git a/src/web/app/mobile/tags/timeline-post-sub.tag b/src/web/app/mobile/tags/timeline-post-sub.tag index 920503ebcc..e6f9df2be6 100644 --- a/src/web/app/mobile/tags/timeline-post-sub.tag +++ b/src/web/app/mobile/tags/timeline-post-sub.tag @@ -1,99 +1,96 @@ -mk-timeline-post-sub - article - a.avatar-anchor(href={ '/' + post.user.username }) - img.avatar(src={ post.user.avatar_url + '?thumbnail&size=96' }, alt='avatar') - div.main - header - a.name(href={ '/' + post.user.username }) - | { post.user.name } - span.username - | @{ post.user.username } - a.created-at(href={ '/' + 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 - - > article - padding 16px - - &:after - content "" +<mk-timeline-post-sub> + <article><a class="avatar-anchor" href="{ '/' + post.user.username }"><img class="avatar" src="{ post.user.avatar_url + '?thumbnail&size=96' }" alt="avatar"/></a> + <div class="main"> + <header><a class="name" href="{ '/' + post.user.username }">{ post.user.name }</a><span class="username">@{ post.user.username }</span><a class="created-at" href="{ '/' + 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 - &:hover - > .main > footer > button - color #888 + > article + padding 16px - > .avatar-anchor - display block - float left - margin 0 10px 0 0 + &:after + content "" + display block + clear both - @media (min-width 500px) - margin-right 16px + &:hover + > .main > footer > button + color #888 - > .avatar - display block - width 44px - height 44px - margin 0 - border-radius 8px - vertical-align bottom + > .avatar-anchor + display block + float left + margin 0 10px 0 0 - @media (min-width 500px) - width 52px - height 52px + @media (min-width 500px) + margin-right 16px - > .main - float left - width calc(100% - 54px) + > .avatar + display block + width 44px + height 44px + margin 0 + border-radius 8px + vertical-align bottom - @media (min-width 500px) - width calc(100% - 68px) + @media (min-width 500px) + width 52px + height 52px - > header - margin-bottom 4px - white-space nowrap + > .main + float left + width calc(100% - 54px) - > .name - display inline - margin 0 - padding 0 - color #607073 - font-size 1em - font-weight 700 - text-align left - text-decoration none + @media (min-width 500px) + 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 - > .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 -script. - @post = @opts.post + > .body + + > .text + cursor default + margin 0 + padding 0 + font-size 1.1em + color #717171 + + </style> + <script>@post = @opts.post</script> +</mk-timeline-post-sub> diff --git a/src/web/app/mobile/tags/timeline-post.tag b/src/web/app/mobile/tags/timeline-post.tag index a71fab26f0..3037b4bef3 100644 --- a/src/web/app/mobile/tags/timeline-post.tag +++ b/src/web/app/mobile/tags/timeline-post.tag @@ -1,296 +1,291 @@ -mk-timeline-post(class={ repost: is-repost }) - - 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 }): img.avatar(src={ post.user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - i.fa.fa-retweet - a.name(href={ CONFIG.url + '/' + post.user.username }) { 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=96' }, alt='avatar') - div.main - header - a.name(href={ CONFIG.url + '/' + p.user.username }) - | { 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 - soan@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 }) - 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 }) - i.fa.fa-thumbs-o-up - p.count(if={ p.likes_count > 0 }) { p.likes_count } - -style. - display block - margin 0 - padding 0 - font-size 12px - - @media (min-width 350px) - font-size 14px - - @media (min-width 500px) - font-size 16px - - > .repost - color #9dbb00 - background linear-gradient(to bottom, #edfde2 0%, #fff 100%) - - > p +<mk-timeline-post class="{ repost: isRepost }"> + <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 }"><img class="avatar" src="{ post.user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/></a><i class="fa fa-retweet"></i><a class="name" href="{ CONFIG.url + '/' + post.user.username }">{ 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&size=96' }" alt="avatar"/></a> + <div class="main"> + <header><a class="name" href="{ CONFIG.url + '/' + p.user.username }">{ 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> + <soan ref="text"></soan><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 }"><i class="fa fa-reply"></i> + <p class="count" if="{ p.replies_count > 0 }">{ p.replies_count }</p> + </button> + <button onclick="{ repost }" title="Repost"><i class="fa fa-retweet"></i> + <p class="count" if="{ p.repost_count > 0 }">{ p.repost_count }</p> + </button> + <button class="{ liked: p.is_liked }" onclick="{ like }"><i class="fa fa-thumbs-o-up"></i> + <p class="count" if="{ p.likes_count > 0 }">{ p.likes_count }</p> + </button> + </footer> + </div> + </article> + <style type="stylus"> + :scope + display block margin 0 - padding 8px 16px - line-height 28px + padding 0 + font-size 12px + + @media (min-width 350px) + font-size 14px @media (min-width 500px) - padding 16px + font-size 16px - .avatar-anchor - display inline-block + > .repost + color #9dbb00 + background linear-gradient(to bottom, #edfde2 0%, #fff 100%) - .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 8px - right 16px - font-size 0.9em - line-height 28px - - @media (min-width 500px) - top 16px - - & + article - padding-top 8px - - > .reply-to - background rgba(0, 0, 0, 0.0125) - - > mk-post-preview - background transparent - - > article - padding 14px 16px 9px 16px - - &:after - content "" - display block - clear both - - > .avatar-anchor - display block - float left - margin 0 10px 0 0 - - @media (min-width 500px) - margin-right 16px - - > .avatar - display block - width 48px - height 48px - margin 0 - border-radius 6px - vertical-align bottom - - @media (min-width 500px) - width 58px - height 58px - border-radius 8px - - > .main - float left - width calc(100% - 58px) - - @media (min-width 500px) - width calc(100% - 74px) - - > header - white-space nowrap - - @media (min-width 500px) - margin-bottom 2px - - > .name - display inline + > p margin 0 - padding 0 - color #777 - font-size 1em - font-weight 700 - text-align left - text-decoration none + padding 8px 16px + line-height 28px - &:hover - text-decoration underline - - > .username - text-align left - margin 0 0 0 8px - color #ccc - - > .created-at - position absolute - top 0 - right 0 - font-size 0.9em - color #c0c0c0 - - > .body - - > .text - cursor default - display block - margin 0 - padding 0 - word-wrap break-word - font-size 1.1em - color #717171 - - mk-url-preview - margin-top 8px - - > .reply - margin-right 8px - color #717171 - - > .quote - margin-left 4px - font-style oblique - color #a0bf46 - - > .media - > img - display block - max-width 100% - - > .repost - margin 8px 0 - - > i:first-child - position absolute - top -8px - left -8px - z-index 1 - color #c0dac6 - font-size 28px - background #fff - - > mk-post-preview + @media (min-width 500px) padding 16px - border dashed 1px #c0dac6 - border-radius 8px - > footer - > button - margin 0 28px 0 0 - padding 8px + .avatar-anchor + display inline-block + + .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 8px + right 16px + font-size 0.9em + line-height 28px + + @media (min-width 500px) + top 16px + + & + article + padding-top 8px + + > .reply-to + background rgba(0, 0, 0, 0.0125) + + > mk-post-preview background transparent - border none - box-shadow none - font-size 1em - color #ddd - cursor pointer - &:hover - color #666 + > article + padding 14px 16px 9px 16px - > .count - display inline - margin 0 0 0 8px - color #999 + &:after + content "" + display block + clear both - &.liked - color $theme-color + > .avatar-anchor + display block + float left + margin 0 10px 0 0 -script. - @mixin \api - @mixin \text - @mixin \get-post-summary - @mixin \open-post-form + @media (min-width 500px) + margin-right 16px - @post = @opts.post - @is-repost = @post.repost? and !@post.text? - @p = if @is-repost then @post.repost else @post - @summary = @get-post-summary @p - @url = CONFIG.url + '/' + @p.user.username + '/' + @p.id + > .avatar + display block + width 48px + height 48px + margin 0 + border-radius 6px + vertical-align bottom - @on \mount ~> - if @p.text? - tokens = if @p._highlight? - then @analyze @p._highlight - else @analyze @p.text + @media (min-width 500px) + width 58px + height 58px + border-radius 8px - @refs.text.innerHTML = if @p._highlight? - then @compile tokens, true, false - else @compile tokens + > .main + float left + width calc(100% - 58px) - @refs.text.children.for-each (e) ~> - if e.tag-name == \MK-URL - riot.mount e + @media (min-width 500px) + width calc(100% - 74px) - # 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 + > header + white-space nowrap - @reply = ~> - @open-post-form do - reply: @p + @media (min-width 500px) + margin-bottom 2px - @repost = ~> - text = window.prompt '「' + @summary + '」をRepost' - if text? - @api \posts/create do - repost_id: @p.id - text: if text == '' then undefined else text + > .name + display inline + margin 0 + padding 0 + color #777 + font-size 1em + font-weight 700 + text-align left + text-decoration none - @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! + &:hover + text-decoration underline + + > .username + text-align left + margin 0 0 0 8px + color #ccc + + > .created-at + position absolute + top 0 + right 0 + font-size 0.9em + color #c0c0c0 + + > .body + + > .text + cursor default + display block + margin 0 + padding 0 + word-wrap break-word + font-size 1.1em + color #717171 + + mk-url-preview + margin-top 8px + + > .reply + margin-right 8px + color #717171 + + > .quote + margin-left 4px + font-style oblique + color #a0bf46 + + > .media + > img + display block + max-width 100% + + > .repost + margin 8px 0 + + > i:first-child + position absolute + top -8px + left -8px + z-index 1 + color #c0dac6 + font-size 28px + background #fff + + > mk-post-preview + padding 16px + border dashed 1px #c0dac6 + border-radius 8px + + > footer + > button + margin 0 28px 0 0 + padding 8px + background transparent + border none + box-shadow none + font-size 1em + color #ddd + cursor pointer + + &:hover + color #666 + + > .count + display inline + margin 0 0 0 8px + color #999 + + &.liked + color $theme-color + + </style> + <script> + @mixin \api + @mixin \text + @mixin \get-post-summary + @mixin \open-post-form + + @post = @opts.post + @is-repost = @post.repost? and !@post.text? + @p = if @is-repost then @post.repost else @post + @summary = @get-post-summary @p + @url = CONFIG.url + '/' + @p.user.username + '/' + @p.id + + @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 = ~> + @open-post-form do + reply: @p + + @repost = ~> + text = window.prompt '「' + @summary + '」をRepost' + if text? + @api \posts/create do + repost_id: @p.id + text: if text == '' then undefined else text + + @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! + </script> +</mk-timeline-post> diff --git a/src/web/app/mobile/tags/timeline.tag b/src/web/app/mobile/tags/timeline.tag index 7114824872..cef05d54a0 100644 --- a/src/web/app/mobile/tags/timeline.tag +++ b/src/web/app/mobile/tags/timeline.tag @@ -1,128 +1,120 @@ -mk-timeline - div.init(if={ init }) - i.fa.fa-spinner.fa-pulse - | 読み込んでいます - div.empty(if={ !init && posts.length == 0 }) - i.fa.fa-comments-o - | { opts.empty || '表示するものがありません' } - 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(if={ !init }) - button(if={ can-fetch-more }, onclick={ more }, disabled={ fetching }) - span(if={ !fetching }) もっとみる - span(if={ fetching }) - | 読み込み中 - mk-ellipsis - -style. - display block - background #fff - background-clip content-box - overflow hidden - - > .init - padding 64px 0 - text-align center - color #999 - - > i - margin-right 4px - - > .empty - margin 0 auto - padding 32px - max-width 400px - text-align center - color #999 - - > i +<mk-timeline> + <div class="init" if="{ init }"><i class="fa fa-spinner fa-pulse"></i>読み込んでいます</div> + <div class="empty" if="{ !init && posts.length == 0 }"><i class="fa fa-comments-o"></i>{ opts.empty || '表示するものがありません' }</div> + <virtual each="{ post, i in posts }"> + <mk-timeline-post post="{ post }"></mk-timeline-post> + <p class="date" if="{ i != posts.length - 1 && 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 if="{ !init }"> + <button if="{ canFetchMore }" onclick="{ more }" disabled="{ fetching }"><span if="{ !fetching }">もっとみる</span><span if="{ fetching }">読み込み中 + <mk-ellipsis></mk-ellipsis></span></button> + </footer> + <style type="stylus"> + :scope display block - margin-bottom 16px - font-size 3em - color #ccc + background #fff + background-clip content-box + overflow hidden - > mk-timeline-post - border-bottom solid 1px #eaeaea + > .init + padding 64px 0 + text-align center + color #999 - &:last-of-type - border-bottom none + > i + margin-right 4px - > .date - display block - margin 0 - line-height 32px - text-align center - font-size 0.9em - color #aaa - background #fdfdfd - border-bottom solid 1px #eaeaea + > .empty + margin 0 auto + padding 32px + max-width 400px + text-align center + color #999 - span - margin 0 16px + > i + display block + margin-bottom 16px + font-size 3em + color #ccc - i - margin-right 8px + > mk-timeline-post + border-bottom solid 1px #eaeaea - > footer - text-align center - border-top solid 1px #eaeaea - border-bottom-left-radius 4px - border-bottom-right-radius 4px + &:last-of-type + border-bottom none - > button - margin 0 - padding 16px - width 100% - color $theme-color + > .date + display block + margin 0 + line-height 32px + text-align center + font-size 0.9em + color #aaa + background #fdfdfd + border-bottom solid 1px #eaeaea - &:disabled - opacity 0.7 + span + margin 0 16px -script. - @posts = [] - @init = true - @fetching = false - @can-fetch-more = true + i + margin-right 8px - @on \mount ~> - @opts.init.then (posts) ~> - @init = false - @set-posts posts + > footer + text-align center + border-top solid 1px #eaeaea + border-bottom-left-radius 4px + border-bottom-right-radius 4px - @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 + '日' + > button + margin 0 + padding 16px + width 100% + color $theme-color - @more = ~> - if @init or @fetching or @posts.length == 0 then return - @fetching = true - @update! - @opts.more!.then (posts) ~> - @fetching = false - @prepend-posts posts + &:disabled + opacity 0.7 - @set-posts = (posts) ~> - @posts = posts - @update! + </style> + <script> + @posts = [] + @init = true + @fetching = false + @can-fetch-more = true - @prepend-posts = (posts) ~> - posts.for-each (post) ~> - @posts.push post + @on \mount ~> + @opts.init.then (posts) ~> + @init = false + @set-posts posts + + @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 + '日' + + @more = ~> + if @init or @fetching or @posts.length == 0 then return + @fetching = true + @update! + @opts.more!.then (posts) ~> + @fetching = false + @prepend-posts posts + + @set-posts = (posts) ~> + @posts = posts @update! - @add-post = (post) ~> - @posts.unshift post - @update! + @prepend-posts = (posts) ~> + posts.for-each (post) ~> + @posts.push post + @update! - @tail = ~> - @posts[@posts.length - 1] + @add-post = (post) ~> + @posts.unshift post + @update! + + @tail = ~> + @posts[@posts.length - 1] + </script> +</mk-timeline> diff --git a/src/web/app/mobile/tags/ui-header.tag b/src/web/app/mobile/tags/ui-header.tag index 7105d065f8..273b03213e 100644 --- a/src/web/app/mobile/tags/ui-header.tag +++ b/src/web/app/mobile/tags/ui-header.tag @@ -1,98 +1,103 @@ -mk-ui-header - mk-special-message - div.main - div.backdrop - div.content - button.nav#hamburger: i.fa.fa-bars - h1@title Misskey - button.post(onclick={ post }): i.fa.fa-pencil +<mk-ui-header> + <mk-special-message></mk-special-message> + <div class="main"> + <div class="backdrop"></div> + <div class="content"> + <button class="nav" id="hamburger"><i class="fa fa-bars"></i></button> + <h1 ref="title">Misskey</h1> + <button class="post" onclick="{ post }"><i class="fa fa-pencil"></i></button> + </div> + </div> + <style type="stylus"> + :scope + $height = 48px -style. - $height = 48px - - display block - position fixed - top 0 - z-index 1024 - width 100% - box-shadow 0 1px 0 rgba(#000, 0.075) - - > .main - color rgba(#000, 0.6) - - > .backdrop - position absolute + display block + position fixed top 0 - z-index 1023 - width 100% - height $height - -webkit-backdrop-filter blur(12px) - backdrop-filter blur(12px) - background-color rgba(#fff, 0.75) - - > .content z-index 1024 + width 100% + box-shadow 0 1px 0 rgba(#000, 0.075) - > h1 - display block - margin 0 auto - padding 0 - width 100% - max-width calc(100% - 112px) - text-align center - font-size 1.1em - font-weight normal - line-height $height - white-space nowrap - overflow hidden - text-overflow ellipsis + > .main + color rgba(#000, 0.6) - > i - margin-right 8px + > .backdrop + position absolute + top 0 + z-index 1023 + width 100% + height $height + -webkit-backdrop-filter blur(12px) + backdrop-filter blur(12px) + background-color rgba(#fff, 0.75) - > img - display inline-block - vertical-align bottom - width ($height - 16px) - height ($height - 16px) - margin 8px - border-radius 6px + > .content + z-index 1024 - > .nav - display block - position absolute - top 0 - left 0 - width $height - font-size 1.4em - line-height $height - border-right solid 1px rgba(#000, 0.1) + > h1 + display block + margin 0 auto + padding 0 + width 100% + max-width calc(100% - 112px) + text-align center + font-size 1.1em + font-weight normal + line-height $height + white-space nowrap + overflow hidden + text-overflow ellipsis - > i - transition all 0.2s ease + > i + margin-right 8px - > .post - display block - position absolute - top 0 - right 0 - width $height - text-align center - font-size 1.4em - color inherit - line-height $height - border-left solid 1px rgba(#000, 0.1) + > img + display inline-block + vertical-align bottom + width ($height - 16px) + height ($height - 16px) + margin 8px + border-radius 6px -script. - @mixin \ui - @mixin \open-post-form + > .nav + display block + position absolute + top 0 + left 0 + width $height + font-size 1.4em + line-height $height + border-right solid 1px rgba(#000, 0.1) - @on \mount ~> - @opts.ready! + > i + transition all 0.2s ease - @ui.one \title (title) ~> - if @refs.title? - @refs.title.innerHTML = title + > .post + display block + position absolute + top 0 + right 0 + width $height + text-align center + font-size 1.4em + color inherit + line-height $height + border-left solid 1px rgba(#000, 0.1) - @post = ~> - @open-post-form! + </style> + <script> + @mixin \ui + @mixin \open-post-form + + @on \mount ~> + @opts.ready! + + @ui.one \title (title) ~> + if @refs.title? + @refs.title.innerHTML = title + + @post = ~> + @open-post-form! + </script> +</mk-ui-header> diff --git a/src/web/app/mobile/tags/ui-nav.tag b/src/web/app/mobile/tags/ui-nav.tag index 2c551b30ad..de9c17cc8f 100644 --- a/src/web/app/mobile/tags/ui-nav.tag +++ b/src/web/app/mobile/tags/ui-nav.tag @@ -1,169 +1,151 @@ -mk-ui-nav - div.body: div.content - a.me(if={ SIGNIN }, href={ CONFIG.url + '/' + I.username }) - img.avatar(src={ I.avatar_url + '?thumbnail&size=128' }, alt='avatar') - p.name { I.name } - div.links - ul - li.post: a(href='/i/post') - i.icon.fa.fa-pencil-square-o - | 新規投稿 - i.angle.fa.fa-angle-right - ul - li.home: a(href='/') - i.icon.fa.fa-home - | ホーム - i.angle.fa.fa-angle-right - li.mentions: a(href='/i/mentions') - i.icon.fa.fa-at - | あなた宛て - i.angle.fa.fa-angle-right - li.notifications: a(href='/i/notifications') - i.icon.fa.fa-bell-o - | 通知 - i.angle.fa.fa-angle-right - li.messaging: a - i.icon.fa.fa-comments-o - | メッセージ - i.angle.fa.fa-angle-right - ul - li.settings: a(onclick={ search }) - i.icon.fa.fa-search - | 検索 - i.angle.fa.fa-angle-right - ul - li.settings: a(href='/i/drive') - i.icon.fa.fa-cloud - | ドライブ - i.angle.fa.fa-angle-right - li.settings: a(href='/i/upload') - i.icon.fa.fa-upload - | アップロード - i.angle.fa.fa-angle-right - ul - li.settings: a(href='/i/settings') - i.icon.fa.fa-cog - | 設定 - i.angle.fa.fa-angle-right - p.about - a Misskeyについて - -style. - display block - position fixed - top 0 - left 0 - z-index -1 - width 240px - color #fff - background #313538 - visibility hidden - - .body - height 100% - overflow hidden - - .content - min-height 100% - - .me - display block - margin 0 - padding 16px - - .avatar - display inline - max-width 64px - border-radius 32px - vertical-align middle - - .name +<mk-ui-nav> + <div class="body"> + <div class="content"><a class="me" if="{ SIGNIN }" href="{ CONFIG.url + '/' + I.username }"><img class="avatar" src="{ I.avatar_url + '?thumbnail&size=128' }" alt="avatar"/> + <p class="name">{ I.name }</p></a> + <div class="links"> + <ul> + <li class="post"><a href="/i/post"><i class="icon fa fa-pencil-square-o"></i>新規投稿<i class="angle fa fa-angle-right"></i></a></li> + </ul> + <ul> + <li class="home"><a href="/"><i class="icon fa fa-home"></i>ホーム<i class="angle fa fa-angle-right"></i></a></li> + <li class="mentions"><a href="/i/mentions"><i class="icon fa fa-at"></i>あなた宛て<i class="angle fa fa-angle-right"></i></a></li> + <li class="notifications"><a href="/i/notifications"><i class="icon fa fa-bell-o"></i>通知<i class="angle fa fa-angle-right"></i></a></li> + <li class="messaging"><a><i class="icon fa fa-comments-o"></i>メッセージ<i class="angle fa fa-angle-right"></i></a></li> + </ul> + <ul> + <li class="settings"><a onclick="{ search }"><i class="icon fa fa-search"></i>検索<i class="angle fa fa-angle-right"></i></a></li> + </ul> + <ul> + <li class="settings"><a href="/i/drive"><i class="icon fa fa-cloud"></i>ドライブ<i class="angle fa fa-angle-right"></i></a></li> + <li class="settings"><a href="/i/upload"><i class="icon fa fa-upload"></i>アップロード<i class="angle fa fa-angle-right"></i></a></li> + </ul> + <ul> + <li class="settings"><a href="/i/settings"><i class="icon fa fa-cog"></i>設定<i class="angle fa fa-angle-right"></i></a></li> + </ul> + </div> + <p class="about"><a>Misskeyについて</a></p> + </div> + </div> + <style type="stylus"> + :scope display block - margin 0 16px - position absolute + position fixed top 0 - left 80px - padding 0 - width calc(100% - 112px) + left 0 + z-index -1 + width 240px color #fff - line-height 96px - overflow hidden - text-overflow ellipsis - white-space nowrap + background #313538 + visibility hidden - ul - display block - margin 16px 0 - padding 0 - list-style none + .body + height 100% + overflow hidden - &:first-child - margin-top 0 + .content + min-height 100% - li - display block - font-size 1em - line-height 1em - border-top solid 1px rgba(0, 0, 0, 0.2) - background #353A3E - background-clip content-box - - &:last-child - border-bottom solid 1px rgba(0, 0, 0, 0.2) - - a + .me display block - padding 0 20px - line-height 3rem - line-height calc(1rem + 30px) - color #eee - text-decoration none + margin 0 + padding 16px - > .icon - margin-right 0.5em + .avatar + display inline + max-width 64px + border-radius 32px + vertical-align middle - > .angle + .name + display block + margin 0 16px position absolute top 0 - right 0 - padding 0 20px - font-size 1.2em - line-height calc(1rem + 30px) - color #ccc - - > .unread-count - position absolute - height calc(0.9em + 10px) - line-height calc(0.9em + 10px) - top 0 - bottom 0 - right 38px - margin auto 0 - padding 0px 8px - min-width 2em - font-size 0.9em - text-align center + left 80px + padding 0 + width calc(100% - 112px) color #fff - background rgba(255, 255, 255, 0.1) - border-radius 1em + line-height 96px + overflow hidden + text-overflow ellipsis + white-space nowrap - .about - margin 1em 1em 2em 1em - text-align center - font-size 0.6em - opacity 0.3 + ul + display block + margin 16px 0 + padding 0 + list-style none - a - color #fff + &:first-child + margin-top 0 -script. - @mixin \i - @mixin \page + li + display block + font-size 1em + line-height 1em + border-top solid 1px rgba(0, 0, 0, 0.2) + background #353A3E + background-clip content-box - @on \mount ~> - @opts.ready! + &:last-child + border-bottom solid 1px rgba(0, 0, 0, 0.2) - @search = ~> - query = window.prompt \検索 - if query? and query != '' - @page '/search:' + query + a + display block + padding 0 20px + line-height 3rem + line-height calc(1rem + 30px) + color #eee + text-decoration none + + > .icon + margin-right 0.5em + + > .angle + position absolute + top 0 + right 0 + padding 0 20px + font-size 1.2em + line-height calc(1rem + 30px) + color #ccc + + > .unread-count + position absolute + height calc(0.9em + 10px) + line-height calc(0.9em + 10px) + top 0 + bottom 0 + right 38px + margin auto 0 + padding 0px 8px + min-width 2em + font-size 0.9em + text-align center + color #fff + background rgba(255, 255, 255, 0.1) + border-radius 1em + + .about + margin 1em 1em 2em 1em + text-align center + font-size 0.6em + opacity 0.3 + + a + color #fff + + </style> + <script> + @mixin \i + @mixin \page + + @on \mount ~> + @opts.ready! + + @search = ~> + query = window.prompt \検索 + if query? and query != '' + @page '/search:' + query + </script> +</mk-ui-nav> diff --git a/src/web/app/mobile/tags/ui.tag b/src/web/app/mobile/tags/ui.tag index 81dfac80ca..966cfb4255 100644 --- a/src/web/app/mobile/tags/ui.tag +++ b/src/web/app/mobile/tags/ui.tag @@ -1,50 +1,51 @@ -mk-ui - div.global@global - mk-ui-header@header(ready={ ready }) - mk-ui-nav@nav(ready={ ready }) +<mk-ui> + <div class="global" ref="global"> + <mk-ui-header ref="header" ready="{ ready }"></mk-ui-header> + <mk-ui-nav ref="nav" ready="{ ready }"></mk-ui-nav> + <div class="content" ref="main"><yield /></div> + </div> + <mk-stream-indicator></mk-stream-indicator> + <style type="stylus"> + :scope + display block - div.content@main - <yield /> + > .global + > .content + background #fff - mk-stream-indicator + </style> + <script> + @mixin \stream -style. - display block + @ready-count = 0 - > .global - > .content - background #fff + #@ui.on \notification (text) ~> + # alert text -script. - @mixin \stream + @on \mount ~> + @stream.on \notification @on-stream-notification + @ready! - @ready-count = 0 + @on \unmount ~> + @stream.off \notification @on-stream-notification + @slide.slide-close! - #@ui.on \notification (text) ~> - # alert text + @ready = ~> + @ready-count++ - @on \mount ~> - @stream.on \notification @on-stream-notification - @ready! + if @ready-count == 2 + @slide = SpSlidemenu @refs.main, @refs.nav.root, \#hamburger {direction: \left} + @init-view-position! - @on \unmount ~> - @stream.off \notification @on-stream-notification - @slide.slide-close! + @init-view-position = ~> + top = @refs.header.root.offset-height + @refs.main.style.padding-top = top + \px + @refs.nav.root.style.margin-top = top + \px + @refs.nav.root.query-selector '.body > .content' .style.padding-bottom = top + \px - @ready = ~> - @ready-count++ - - if @ready-count == 2 - @slide = SpSlidemenu @refs.main, @refs.nav.root, \#hamburger {direction: \left} - @init-view-position! - - @init-view-position = ~> - top = @refs.header.root.offset-height - @refs.main.style.padding-top = top + \px - @refs.nav.root.style.margin-top = top + \px - @refs.nav.root.query-selector '.body > .content' .style.padding-bottom = top + \px - - @on-stream-notification = (notification) ~> - el = document.body.append-child document.create-element \mk-notify - riot.mount el, do - notification: notification + @on-stream-notification = (notification) ~> + el = document.body.append-child document.create-element \mk-notify + riot.mount el, do + notification: notification + </script> +</mk-ui> diff --git a/src/web/app/mobile/tags/user-followers.tag b/src/web/app/mobile/tags/user-followers.tag index 7004398268..00d11f3970 100644 --- a/src/web/app/mobile/tags/user-followers.tag +++ b/src/web/app/mobile/tags/user-followers.tag @@ -1,22 +1,25 @@ -mk-user-followers - mk-users-list@list(fetch={ fetch }, count={ user.followers_count }, you-know-count={ user.followers_you_know_count }, no-users={ 'フォロワーはいないようです。' }) +<mk-user-followers> + <mk-users-list ref="list" fetch="{ fetch }" count="{ user.followers_count }" you-know-count="{ user.followers_you_know_count }" no-users="{ 'フォロワーはいないようです。' }"></mk-users-list> + <style type="stylus"> + :scope + display block -style. - display block + </style> + <script> + @mixin \api -script. - @mixin \api + @user = @opts.user - @user = @opts.user + @fetch = (iknow, limit, cursor, cb) ~> + @api \users/followers do + user_id: @user.id + iknow: iknow + limit: limit + cursor: if cursor? then cursor else undefined + .then cb - @fetch = (iknow, limit, cursor, cb) ~> - @api \users/followers do - user_id: @user.id - iknow: iknow - limit: limit - cursor: if cursor? then cursor else undefined - .then cb - - @on \mount ~> - @refs.list.on \loaded ~> - @trigger \loaded + @on \mount ~> + @refs.list.on \loaded ~> + @trigger \loaded + </script> +</mk-user-followers> diff --git a/src/web/app/mobile/tags/user-following.tag b/src/web/app/mobile/tags/user-following.tag index c122acd607..bbfa547c79 100644 --- a/src/web/app/mobile/tags/user-following.tag +++ b/src/web/app/mobile/tags/user-following.tag @@ -1,22 +1,25 @@ -mk-user-following - mk-users-list@list(fetch={ fetch }, count={ user.following_count }, you-know-count={ user.following_you_know_count }, no-users={ 'フォロー中のユーザーはいないようです。' }) +<mk-user-following> + <mk-users-list ref="list" fetch="{ fetch }" count="{ user.following_count }" you-know-count="{ user.following_you_know_count }" no-users="{ 'フォロー中のユーザーはいないようです。' }"></mk-users-list> + <style type="stylus"> + :scope + display block -style. - display block + </style> + <script> + @mixin \api -script. - @mixin \api + @user = @opts.user - @user = @opts.user + @fetch = (iknow, limit, cursor, cb) ~> + @api \users/following do + user_id: @user.id + iknow: iknow + limit: limit + cursor: if cursor? then cursor else undefined + .then cb - @fetch = (iknow, limit, cursor, cb) ~> - @api \users/following do - user_id: @user.id - iknow: iknow - limit: limit - cursor: if cursor? then cursor else undefined - .then cb - - @on \mount ~> - @refs.list.on \loaded ~> - @trigger \loaded + @on \mount ~> + @refs.list.on \loaded ~> + @trigger \loaded + </script> +</mk-user-following> diff --git a/src/web/app/mobile/tags/user-preview.tag b/src/web/app/mobile/tags/user-preview.tag index 56bd93825c..7b00043a1c 100644 --- a/src/web/app/mobile/tags/user-preview.tag +++ b/src/web/app/mobile/tags/user-preview.tag @@ -1,92 +1,89 @@ -mk-user-preview - a.avatar-anchor(href={ CONFIG.url + '/' + user.username }) - img.avatar(src={ user.avatar_url + '?thumbnail&size=64' }, alt='avatar') - div.main - header - a.name(href={ CONFIG.url + '/' + user.username }) - | { user.name } - span.username - | @{ user.username } - div.body - div.bio { user.bio } - -style. - display block - margin 0 - padding 16px - font-size 12px - - @media (min-width 350px) - font-size 14px - - @media (min-width 500px) - font-size 16px - - &:after - content "" - display block - clear both - - > .avatar-anchor - display block - float left - margin 0 10px 0 0 - - @media (min-width 500px) - margin-right 16px - - > .avatar +<mk-user-preview><a class="avatar-anchor" href="{ CONFIG.url + '/' + user.username }"><img class="avatar" src="{ user.avatar_url + '?thumbnail&size=64' }" alt="avatar"/></a> + <div class="main"> + <header><a class="name" href="{ CONFIG.url + '/' + user.username }">{ user.name }</a><span class="username">@{ user.username }</span></header> + <div class="body"> + <div class="bio">{ user.bio }</div> + </div> + </div> + <style type="stylus"> + :scope display block - width 48px - height 48px margin 0 - border-radius 6px - vertical-align bottom + padding 16px + font-size 12px + + @media (min-width 350px) + font-size 14px @media (min-width 500px) - width 58px - height 58px - border-radius 8px + font-size 16px - > .main - float left - width calc(100% - 58px) - - @media (min-width 500px) - width calc(100% - 74px) - - > header - @media (min-width 500px) - margin-bottom 2px - - > .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 - - > .bio - cursor default + &:after + content "" display block - margin 0 - padding 0 - word-wrap break-word - font-size 1.1em - color #717171 + clear both -script. - @user = @opts.user + > .avatar-anchor + display block + float left + margin 0 10px 0 0 + + @media (min-width 500px) + margin-right 16px + + > .avatar + display block + width 48px + height 48px + margin 0 + border-radius 6px + vertical-align bottom + + @media (min-width 500px) + width 58px + height 58px + border-radius 8px + + > .main + float left + width calc(100% - 58px) + + @media (min-width 500px) + width calc(100% - 74px) + + > header + @media (min-width 500px) + margin-bottom 2px + + > .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 + + > .bio + cursor default + display block + margin 0 + padding 0 + word-wrap break-word + font-size 1.1em + color #717171 + + </style> + <script>@user = @opts.user</script> +</mk-user-preview> diff --git a/src/web/app/mobile/tags/user-timeline.tag b/src/web/app/mobile/tags/user-timeline.tag index 848405d24e..354c0790c2 100644 --- a/src/web/app/mobile/tags/user-timeline.tag +++ b/src/web/app/mobile/tags/user-timeline.tag @@ -1,28 +1,31 @@ -mk-user-timeline - mk-timeline@timeline(init={ init }, more={ more }, empty={ with-media ? 'メディア付き投稿はありません。' : 'このユーザーはまだ投稿していないようです。' }) +<mk-user-timeline> + <mk-timeline ref="timeline" init="{ init }" more="{ more }" empty="{ withMedia ? 'メディア付き投稿はありません。' : 'このユーザーはまだ投稿していないようです。' }"></mk-timeline> + <style type="stylus"> + :scope + display block + max-width 600px + margin 0 auto + background #fff -style. - display block - max-width 600px - margin 0 auto - background #fff + </style> + <script> + @mixin \api -script. - @mixin \api + @user = @opts.user + @with-media = @opts.with-media - @user = @opts.user - @with-media = @opts.with-media + @init = new Promise (res, rej) ~> + @api \users/posts do + user_id: @user.id + with_media: @with-media + .then (posts) ~> + res posts + @trigger \loaded - @init = new Promise (res, rej) ~> - @api \users/posts do - user_id: @user.id - with_media: @with-media - .then (posts) ~> - res posts - @trigger \loaded - - @more = ~> - @api \users/posts do - user_id: @user.id - with_media: @with-media - max_id: @refs.timeline.tail!.id + @more = ~> + @api \users/posts do + user_id: @user.id + with_media: @with-media + max_id: @refs.timeline.tail!.id + </script> +</mk-user-timeline> diff --git a/src/web/app/mobile/tags/user.tag b/src/web/app/mobile/tags/user.tag index 1ecbc3d99e..bce6c883f5 100644 --- a/src/web/app/mobile/tags/user.tag +++ b/src/web/app/mobile/tags/user.tag @@ -1,201 +1,189 @@ -mk-user - div.user(if={ !fetching }) - header - div.banner(style={ user.banner_url ? 'background-image: url(' + user.banner_url + '?thumbnail&size=1024)' : '' }) - div.body - div.top - a.avatar: img(src={ user.avatar_url + '?thumbnail&size=160' }, alt='avatar') - mk-follow-button(if={ SIGNIN && I.id != user.id }, user={ user }) +<mk-user> + <div class="user" if="{ !fetching }"> + <header> + <div class="banner" style="{ user.banner_url ? 'background-image: url(' + user.banner_url + '?thumbnail&size=1024)' : '' }"></div> + <div class="body"> + <div class="top"><a class="avatar"><img src="{ user.avatar_url + '?thumbnail&size=160' }" alt="avatar"/></a> + <mk-follow-button if="{ SIGNIN && I.id != user.id }" user="{ user }"></mk-follow-button> + </div> + <div class="title"> + <h1>{ user.name }</h1><span class="username">@{ user.username }</span><span class="followed" if="{ user.is_followed }">フォローされています</span> + </div> + <div class="bio">{ user.bio }</div> + <div class="info"> + <p class="location" if="{ user.location }"><i class="fa fa-map-marker"></i>{ user.location }</p> + <p class="birthday" if="{ user.birthday }"><i class="fa fa-birthday-cake"></i>{ user.birthday.replace('-', '年').replace('-', '月') + '日' }</p> + </div> + <div class="friends"><a href="{ user.username }/following"><b>{ user.following_count }</b><i>フォロー</i></a><a href="{ user.username }/followers"><b>{ user.followers_count }</b><i>フォロワー</i></a></div> + </div> + <nav><a data-is-active="{ page == 'posts' }" onclick="{ goPosts }">投稿</a><a data-is-active="{ page == 'media' }" onclick="{ goMedia }">メディア</a><a data-is-active="{ page == 'graphs' }" onclick="{ goGraphs }">グラフ</a><a data-is-active="{ page == 'likes' }" onclick="{ goLikes }">いいね</a></nav> + </header> + <div class="body"> + <mk-user-timeline if="{ page == 'posts' }" user="{ user }"></mk-user-timeline> + <mk-user-timeline if="{ page == 'media' }" user="{ user }" with-media="{ true }"></mk-user-timeline> + <mk-user-graphs if="{ page == 'graphs' }" user="{ user }"></mk-user-graphs> + </div> + </div> + <style type="stylus"> + :scope + display block - div.title - h1 { user.name } - span.username @{ user.username } - span.followed(if={ user.is_followed }) フォローされています + > .user + > header + > .banner + padding-bottom 33.3% + background-color #f5f5f5 + background-size cover + background-position center - div.bio { user.bio } + > .body + padding 8px + margin 0 auto + max-width 600px - div.info - p.location(if={ user.location }) - i.fa.fa-map-marker - | { user.location } - p.birthday(if={ user.birthday }) - i.fa.fa-birthday-cake - | { user.birthday.replace('-', '年').replace('-', '月') + '日' } + > .top + &:after + content '' + display block + clear both - div.friends - a(href='{ user.username }/following') - b { user.following_count } - i フォロー - a(href='{ user.username }/followers') - b { user.followers_count } - i フォロワー - nav - a(data-is-active={ page == 'posts' }, onclick={ go-posts }) 投稿 - a(data-is-active={ page == 'media' }, onclick={ go-media }) メディア - a(data-is-active={ page == 'graphs' }, onclick={ go-graphs }) グラフ - a(data-is-active={ page == 'likes' }, onclick={ go-likes }) いいね + > .avatar + display block + float left + width 25% + height 40px - div.body - mk-user-timeline(if={ page == 'posts' }, user={ user }) - mk-user-timeline(if={ page == 'media' }, user={ user }, with-media={ true }) - mk-user-graphs(if={ page == 'graphs' }, user={ user }) + > img + display block + position absolute + left -2px + bottom -2px + width 100% + border 2px solid #fff + border-radius 6px -style. - display block + @media (min-width 500px) + left -4px + bottom -4px + border 4px solid #fff + border-radius 12px - > .user - > header - > .banner - padding-bottom 33.3% - background-color #f5f5f5 - background-size cover - background-position center + > mk-follow-button + float right + height 40px - > .body - padding 8px - margin 0 auto - max-width 600px + > .title + margin 8px 0 - > .top - &:after - content '' - display block - clear both + > h1 + margin 0 + line-height 22px + font-size 20px + color #222 - > .avatar - display block - float left - width 25% - height 40px + > .username + display inline-block + line-height 20px + font-size 16px + font-weight bold + color #657786 - > img + > .followed + margin-left 8px + padding 2px 4px + font-size 12px + color #657786 + background #f8f8f8 + border-radius 4px + + > .bio + margin 8px 0 + color #333 + + > .info + margin 8px 0 + + > p + display inline + margin 0 16px 0 0 + color #555 + + > i + margin-right 4px + + > .friends + > a + color #657786 + + &:first-child + margin-right 16px + + > b + margin-right 4px + font-size 16px + color #14171a + + > i + font-size 14px + + > nav + display flex + justify-content center + margin 0 auto + max-width 600px + border-bottom solid 1px #ddd + + > a display block - position absolute - left -2px - bottom -2px - width 100% - border 2px solid #fff - border-radius 6px - - @media (min-width 500px) - left -4px - bottom -4px - border 4px solid #fff - border-radius 12px - - > mk-follow-button - float right - height 40px - - > .title - margin 8px 0 - - > h1 - margin 0 - line-height 22px - font-size 20px - color #222 - - > .username - display inline-block - line-height 20px - font-size 16px - font-weight bold - color #657786 - - > .followed - margin-left 8px - padding 2px 4px - font-size 12px - color #657786 - background #f8f8f8 - border-radius 4px - - > .bio - margin 8px 0 - color #333 - - > .info - margin 8px 0 - - > p - display inline - margin 0 16px 0 0 - color #555 - - > i - margin-right 4px - - > .friends - > a - color #657786 - - &:first-child - margin-right 16px - - > b - margin-right 4px - font-size 16px - color #14171a - - > i + flex 1 1 + text-align center + line-height 52px font-size 14px + text-decoration none + color #657786 + border-bottom solid 2px transparent - > nav - display flex - justify-content center - margin 0 auto - max-width 600px - border-bottom solid 1px #ddd + &[data-is-active] + font-weight bold + color $theme-color + border-color $theme-color - > a - display block - flex 1 1 - text-align center - line-height 52px - font-size 14px - text-decoration none - color #657786 - border-bottom solid 2px transparent + > .body + @media (min-width 500px) + padding 16px 0 0 0 - &[data-is-active] - font-weight bold - color $theme-color - border-color $theme-color + </style> + <script> + @mixin \i + @mixin \api - > .body - @media (min-width 500px) - padding 16px 0 0 0 + @username = @opts.user + @page = if @opts.page? then @opts.page else \posts + @fetching = true -script. - @mixin \i - @mixin \api + @on \mount ~> + @api \users/show do + username: @username + .then (user) ~> + @fetching = false + @user = user + @trigger \loaded user + @update! - @username = @opts.user - @page = if @opts.page? then @opts.page else \posts - @fetching = true - - @on \mount ~> - @api \users/show do - username: @username - .then (user) ~> - @fetching = false - @user = user - @trigger \loaded user + @go-posts = ~> + @page = \posts @update! - @go-posts = ~> - @page = \posts - @update! + @go-media = ~> + @page = \media + @update! - @go-media = ~> - @page = \media - @update! + @go-graphs = ~> + @page = \graphs + @update! - @go-graphs = ~> - @page = \graphs - @update! - - @go-likes = ~> - @page = \likes - @update! + @go-likes = ~> + @page = \likes + @update! + </script> +</mk-user> diff --git a/src/web/app/mobile/tags/users-list.tag b/src/web/app/mobile/tags/users-list.tag index 3e29a0a4cc..f64f196e46 100644 --- a/src/web/app/mobile/tags/users-list.tag +++ b/src/web/app/mobile/tags/users-list.tag @@ -1,125 +1,116 @@ -mk-users-list - nav - span(data-is-active={ mode == 'all' }, onclick={ set-mode.bind(this, 'all') }) - | すべて - span { opts.count } - // ↓ https://github.com/riot/riot/issues/2080 - span(if={ SIGNIN && opts.you-know-count != '' }, data-is-active={ mode == 'iknow' }, onclick={ set-mode.bind(this, 'iknow') }) - | 知り合い - span { opts.you-know-count } - - div.users(if={ !fetching && users.length != 0 }) - mk-user-preview(each={ users }, user={ this }) - - button.more(if={ !fetching && next != null }, onclick={ more }, disabled={ more-fetching }) - span(if={ !more-fetching }) もっと - span(if={ more-fetching }) - | 読み込み中 - mk-ellipsis - - p.no(if={ !fetching && users.length == 0 }) - | { opts.no-users } - p.fetching(if={ fetching }) - i.fa.fa-spinner.fa-pulse.fa-fw - | 読み込んでいます - mk-ellipsis - -style. - display block - background #fff - - > nav - display flex - justify-content center - margin 0 auto - max-width 600px - border-bottom solid 1px #ddd - - > span +<mk-users-list> + <nav><span data-is-active="{ mode == 'all' }" onclick="{ setMode.bind(this, 'all') }">すべて<span>{ opts.count }</span></span> + <!-- ↓ https://github.com/riot/riot/issues/2080--><span if="{ SIGNIN && opts.youKnowCount != '' }" data-is-active="{ mode == 'iknow' }" onclick="{ setMode.bind(this, 'iknow') }">知り合い<span>{ opts.youKnowCount }</span></span> + </nav> + <div class="users" if="{ !fetching && users.length != 0 }"> + <mk-user-preview each="{ users }" user="{ this }"></mk-user-preview> + </div> + <button class="more" if="{ !fetching && next != null }" onclick="{ more }" disabled="{ moreFetching }"><span if="{ !moreFetching }">もっと</span><span if="{ moreFetching }">読み込み中 + <mk-ellipsis></mk-ellipsis></span></button> + <p class="no" if="{ !fetching && users.length == 0 }">{ opts.noUsers }</p> + <p class="fetching" if="{ fetching }"><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます + <mk-ellipsis></mk-ellipsis> + </p> + <style type="stylus"> + :scope display block - flex 1 1 - text-align center - line-height 52px - font-size 14px - color #657786 - border-bottom solid 2px transparent + background #fff - &[data-is-active] - font-weight bold - color $theme-color - border-color $theme-color + > nav + display flex + justify-content center + margin 0 auto + max-width 600px + border-bottom solid 1px #ddd - > span - display inline-block - margin-left 4px - padding 2px 5px - font-size 12px - line-height 1 - color #888 - background #eee - border-radius 20px + > span + display block + flex 1 1 + text-align center + line-height 52px + font-size 14px + color #657786 + border-bottom solid 2px transparent - > .users - > * - max-width 600px - margin 0 auto - border-bottom solid 1px rgba(0, 0, 0, 0.05) + &[data-is-active] + font-weight bold + color $theme-color + border-color $theme-color - > .no - margin 0 - padding 16px - text-align center - color #aaa + > span + display inline-block + margin-left 4px + padding 2px 5px + font-size 12px + line-height 1 + color #888 + background #eee + border-radius 20px - > .fetching - margin 0 - padding 16px - text-align center - color #aaa + > .users + > * + max-width 600px + margin 0 auto + border-bottom solid 1px rgba(0, 0, 0, 0.05) - > i - margin-right 4px + > .no + margin 0 + padding 16px + text-align center + color #aaa -script. - @mixin \i + > .fetching + margin 0 + padding 16px + text-align center + color #aaa - @limit = 30users - @mode = \all + > i + margin-right 4px - @fetching = true - @more-fetching = false + </style> + <script> + @mixin \i - @on \mount ~> - @fetch ~> - @trigger \loaded + @limit = 30users + @mode = \all - @fetch = (cb) ~> @fetching = true - @update! - obj <~ @opts.fetch do - @mode == \iknow - @limit - null - @users = obj.users - @next = obj.next - @fetching = false - @update! - if cb? then cb! - - @more = ~> - @more-fetching = true - @update! - obj <~ @opts.fetch do - @mode == \iknow - @limit - @cursor - @users = @users.concat obj.users - @next = obj.next @more-fetching = false - @update! - @set-mode = (mode) ~> - @update do - mode: mode + @on \mount ~> + @fetch ~> + @trigger \loaded - @fetch! + @fetch = (cb) ~> + @fetching = true + @update! + obj <~ @opts.fetch do + @mode == \iknow + @limit + null + @users = obj.users + @next = obj.next + @fetching = false + @update! + if cb? then cb! + + @more = ~> + @more-fetching = true + @update! + obj <~ @opts.fetch do + @mode == \iknow + @limit + @cursor + @users = @users.concat obj.users + @next = obj.next + @more-fetching = false + @update! + + @set-mode = (mode) ~> + @update do + mode: mode + + @fetch! + </script> +</mk-users-list>