This commit is contained in:
		
							parent
							
								
									8b273e215f
								
							
						
					
					
						commit
						520299c2b4
					
				
					 169 changed files with 14582 additions and 14865 deletions
				
			
		
							
								
								
									
										323
									
								
								gulpfile.ts
									
										
									
									
									
								
							
							
						
						
									
										323
									
								
								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; | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -1,29 +1,28 @@ | |||
| mk-drive-browser-window | ||||
| 	mk-window@window(is-modal={ false }, width={ '800px' }, height={ '500px' }) | ||||
| 		<yield to="header"> | ||||
| 		i.fa.fa-cloud | ||||
| 		| ドライブ | ||||
| 		</yield> | ||||
| 		<yield to="content"> | ||||
| 		mk-drive-browser(multiple={ true }, folder={ parent.folder }) | ||||
| 		</yield> | ||||
| <mk-drive-browser-window> | ||||
| 	<mk-window ref="window" is-modal="{ false }" width="{ '800px' }" height="{ '500px' }"><yield to="header"><i class="fa fa-cloud"></i>ドライブ</yield> | ||||
| <yield to="content"> | ||||
| 		<mk-drive-browser multiple="{ true }" folder="{ parent.folder }"></mk-drive-browser></yield> | ||||
| 	</mk-window> | ||||
| 	<style type="stylus"> | ||||
| 		:scope | ||||
| 			> mk-window | ||||
| 				[data-yield='header'] | ||||
| 					> i | ||||
| 						margin-right 4px | ||||
| 
 | ||||
| style. | ||||
| 	> mk-window | ||||
| 		[data-yield='header'] | ||||
| 			> i | ||||
| 				margin-right 4px | ||||
| 				[data-yield='content'] | ||||
| 					> mk-drive-browser | ||||
| 						height 100% | ||||
| 
 | ||||
| 		[data-yield='content'] | ||||
| 			> mk-drive-browser | ||||
| 				height 100% | ||||
| 	</style> | ||||
| 	<script> | ||||
| 		@folder = if @opts.folder? then @opts.folder else null | ||||
| 
 | ||||
| script. | ||||
| 	@folder = if @opts.folder? then @opts.folder else null | ||||
| 		@on \mount ~> | ||||
| 			@refs.window.on \closed ~> | ||||
| 				@unmount! | ||||
| 
 | ||||
| 	@on \mount ~> | ||||
| 		@refs.window.on \closed ~> | ||||
| 			@unmount! | ||||
| 
 | ||||
| 	@close = ~> | ||||
| 		@refs.window.close! | ||||
| 		@close = ~> | ||||
| 			@refs.window.close! | ||||
| 	</script> | ||||
| </mk-drive-browser-window> | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue