From f2fea7f3cd5a131f994ad9bc1d2b4833865dd165 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 20 Apr 2018 03:41:24 +0900
Subject: [PATCH] [wip] darkmode

---
 src/client/app/boot.js                        |  8 +++++
 src/client/app/desktop/script.ts              | 25 ++++++++++++++
 src/client/app/desktop/style.styl             |  3 ++
 .../desktop/views/components/notes.note.vue   | 34 +++++++++++--------
 .../app/desktop/views/components/notes.vue    | 16 ++++++---
 .../app/desktop/views/components/settings.vue | 16 ++++++---
 .../app/desktop/views/components/timeline.vue | 16 ++++++---
 .../desktop/views/components/ui.header.vue    |  4 +--
 .../views/components/widget-container.vue     | 23 +++++++++----
 .../app/desktop/views/components/window.vue   | 22 +++++++-----
 src/client/app/init.css                       |  7 ++++
 11 files changed, 130 insertions(+), 44 deletions(-)

diff --git a/src/client/app/boot.js b/src/client/app/boot.js
index a0709842b9..ac90fda05f 100644
--- a/src/client/app/boot.js
+++ b/src/client/app/boot.js
@@ -62,6 +62,14 @@
 		app = isMobile ? 'mobile' : 'desktop';
 	}
 
+	// Dark/Light
+	const me = JSON.parse(localStorage.getItem('me') || null);
+	if (me && me.clientSettings) {
+		if ((app == 'desktop' && me.clientSettings.dark) || (app == 'mobile' && me.clientSettings.darkMobile)) {
+			document.documentElement.setAttribute('data-darkmode', 'true');
+		}
+	}
+
 	// Script version
 	const ver = localStorage.getItem('v') || VERSION;
 
diff --git a/src/client/app/desktop/script.ts b/src/client/app/desktop/script.ts
index b3152e708b..ba7a64ff22 100644
--- a/src/client/app/desktop/script.ts
+++ b/src/client/app/desktop/script.ts
@@ -2,6 +2,7 @@
  * Desktop Client
  */
 
+import Vue from 'vue';
 import VueRouter from 'vue-router';
 
 // Style
@@ -43,6 +44,30 @@ init(async (launch) => {
 	require('./views/components');
 	require('./views/widgets');
 
+	// Dark/Light
+	Vue.mixin({
+		mounted() {
+			const set = () => {
+				if (!this.$el || !this.os || !this.os.i) return;
+				if (this.os.i.clientSettings.dark) {
+					document.documentElement.setAttribute('data-darkmode', 'true');
+					this.$el.setAttribute('data-darkmode', 'true');
+				} else {
+					document.documentElement.removeAttribute('data-darkmode');
+					this.$el.removeAttribute('data-darkmode');
+				}
+			};
+
+			set();
+
+			this.$watch('os.i.clientSettings', i => {
+				set();
+			}, {
+				deep: true
+			});
+		}
+	});
+
 	// Init router
 	const router = new VueRouter({
 		mode: 'history',
diff --git a/src/client/app/desktop/style.styl b/src/client/app/desktop/style.styl
index 49f71fbde7..6c83cad2b1 100644
--- a/src/client/app/desktop/style.styl
+++ b/src/client/app/desktop/style.styl
@@ -44,6 +44,9 @@ html
 	height 100%
 	background #f7f7f7
 
+	&[data-darkmode]
+		background #191B22
+
 body
 	display flex
 	flex-direction column
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index 873d724b25..6a12071537 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -291,11 +291,11 @@ export default Vue.extend({
 <style lang="stylus" scoped>
 @import '~const.styl'
 
-.note
+root(isDark)
 	margin 0
 	padding 0
-	background #fff
-	border-bottom solid 1px #eaeaea
+	background isDark ? #282C37 : #fff
+	border-bottom solid 1px isDark ? #1c2023 : #eaeaea
 
 	&:first-child
 		border-top-left-radius 6px
@@ -374,7 +374,7 @@ export default Vue.extend({
 
 		&:hover
 			> .main > footer > button
-				color #888
+				color isDark ? #707b97 : #888
 
 		> .avatar-anchor
 			display block
@@ -407,7 +407,7 @@ export default Vue.extend({
 					margin 0 .5em 0 0
 					padding 0
 					overflow hidden
-					color #627079
+					color isDark ? #fff : #627079
 					font-size 1em
 					font-weight bold
 					text-decoration none
@@ -426,7 +426,7 @@ export default Vue.extend({
 
 				> .username
 					margin 0 .5em 0 0
-					color #ccc
+					color isDark ? #606984 : #ccc
 
 				> .info
 					margin-left auto
@@ -443,7 +443,7 @@ export default Vue.extend({
 						border-right solid 1px #eaeaea
 
 					> .created-at
-						color #c0c0c0
+						color isDark ? #606984 : #c0c0c0
 
 			> .body
 
@@ -454,7 +454,7 @@ export default Vue.extend({
 					padding 0
 					overflow-wrap break-word
 					font-size 1.1em
-					color #717171
+					color isDark ? #fff : #717171
 
 					>>> .title
 						display block
@@ -462,7 +462,7 @@ export default Vue.extend({
 						padding 4px
 						font-size 90%
 						text-align center
-						background #eef1f3
+						background isDark ? #2f3944 : #eef1f3
 						border-radius 4px
 
 					>>> .code
@@ -471,12 +471,12 @@ export default Vue.extend({
 					>>> .quote
 						margin 8px
 						padding 6px 12px
-						color #aaa
-						border-left solid 3px #eee
+						color isDark ? #6f808e : #aaa
+						border-left solid 3px isDark ? #637182 : #eee
 
 					> .reply
 						margin-right 8px
-						color #717171
+						color isDark ? #99abbf : #717171
 
 					> .rp
 						margin-left 4px
@@ -547,13 +547,13 @@ export default Vue.extend({
 					padding 0 8px
 					line-height 32px
 					font-size 1em
-					color #ddd
+					color isDark ? #606984 : #ddd
 					background transparent
 					border none
 					cursor pointer
 
 					&:hover
-						color #666
+						color isDark ? #9198af : #666
 
 					> .count
 						display inline
@@ -572,6 +572,12 @@ export default Vue.extend({
 		padding-top 4px
 		background rgba(0, 0, 0, 0.0125)
 
+.note[data-darkmode]
+	root(true)
+
+.note:not([data-darkmode])
+	root(false)
+
 </style>
 
 <style lang="stylus" module>
diff --git a/src/client/app/desktop/views/components/notes.vue b/src/client/app/desktop/views/components/notes.vue
index b5f6957a16..14834f0962 100644
--- a/src/client/app/desktop/views/components/notes.vue
+++ b/src/client/app/desktop/views/components/notes.vue
@@ -50,17 +50,16 @@ export default Vue.extend({
 </script>
 
 <style lang="stylus" scoped>
-.mk-notes
-
+root(isDark)
 	> .date
 		display block
 		margin 0
 		line-height 32px
 		font-size 14px
 		text-align center
-		color #aaa
-		background #fdfdfd
-		border-bottom solid 1px #eaeaea
+		color isDark ? #666b79 : #aaa
+		background isDark ? #242731 : #fdfdfd
+		border-bottom solid 1px isDark ? #1c2023 : #eaeaea
 
 		span
 			margin 0 16px
@@ -86,4 +85,11 @@ export default Vue.extend({
 
 			&:active
 				background #eee
+
+.mk-notes[data-darkmode]
+	root(true)
+
+.mk-notes:not([data-darkmode])
+	root(false)
+
 </style>
diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue
index f9d9bab187..ffa82b9e02 100644
--- a/src/client/app/desktop/views/components/settings.vue
+++ b/src/client/app/desktop/views/components/settings.vue
@@ -37,14 +37,17 @@
 		<section class="web" v-show="page == 'web'">
 			<h1>デザインと表示</h1>
 			<div class="div">
-				<button class="ui button" @click="customizeHome">ホームをカスタマイズ</button>
+				<button class="ui button" @click="customizeHome" style="margin-bottom: 16px">ホームをカスタマイズ</button>
+			</div>
+			<div class="div">
+				<mk-switch v-model="os.i.clientSettings.dark" @change="onChangeDark" text="ダークモード"/>
+				<mk-switch v-model="os.i.clientSettings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="ウィンドウのタイトルバーにグラデーションを使用"/>
 			</div>
 			<mk-switch v-model="os.i.clientSettings.showPostFormOnTopOfTl" @change="onChangeShowPostFormOnTopOfTl" text="タイムライン上部に投稿フォームを表示する"/>
 			<mk-switch v-model="os.i.clientSettings.showReplyTarget" @change="onChangeShowReplyTarget" text="リプライ先を表示する"/>
 			<mk-switch v-model="os.i.clientSettings.showMaps" @change="onChangeShowMaps" text="マップの自動展開">
 				<span>位置情報が添付された投稿のマップを自動的に展開します。</span>
 			</mk-switch>
-			<mk-switch v-model="os.i.clientSettings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="ウィンドウのタイトルバーにグラデーションを使用"/>
 		</section>
 
 		<section class="web" v-show="page == 'web'">
@@ -298,6 +301,12 @@ export default Vue.extend({
 				autoWatch: v
 			});
 		},
+		onChangeDark(v) {
+			(this as any).api('i/update_client_setting', {
+				name: 'dark',
+				value: v
+			});
+		},
 		onChangeShowPostFormOnTopOfTl(v) {
 			(this as any).api('i/update_client_setting', {
 				name: 'showPostFormOnTopOfTl',
@@ -431,7 +440,6 @@ export default Vue.extend({
 		> .web
 			> .div
 				border-bottom solid 1px #eee
-				padding 0 0 16px 0
-				margin 0 0 16px 0
+				margin 16px 0
 
 </style>
diff --git a/src/client/app/desktop/views/components/timeline.vue b/src/client/app/desktop/views/components/timeline.vue
index c99fabcc60..12f928d15d 100644
--- a/src/client/app/desktop/views/components/timeline.vue
+++ b/src/client/app/desktop/views/components/timeline.vue
@@ -66,14 +66,16 @@ export default Vue.extend({
 <style lang="stylus" scoped>
 @import '~const.styl'
 
-.mk-timeline
-	background #fff
+root(isDark)
+	background isDark ? #282C37 : #fff
 	border solid 1px rgba(0, 0, 0, 0.075)
 	border-radius 6px
 
 	> header
 		padding 0 8px
 		z-index 10
+		background isDark ? #313543 : #fff
+		border-radius 6px 6px 0 0
 		box-shadow 0 1px rgba(0, 0, 0, 0.08)
 
 		> span
@@ -99,10 +101,16 @@ export default Vue.extend({
 					background $theme-color
 
 			&:not([data-is-active])
-				color #6f7477
+				color isDark ? #9aa2a7 : #6f7477
 				cursor pointer
 
 				&:hover
-					color #525a5f
+					color isDark ? #d9dcde : #525a5f
+
+.mk-timeline[data-darkmode]
+	root(true)
+
+.mk-timeline:not([data-darkmode])
+	root(false)
 
 </style>
diff --git a/src/client/app/desktop/views/components/ui.header.vue b/src/client/app/desktop/views/components/ui.header.vue
index 2b63030cd2..96c26367f5 100644
--- a/src/client/app/desktop/views/components/ui.header.vue
+++ b/src/client/app/desktop/views/components/ui.header.vue
@@ -169,10 +169,10 @@ root(isDark)
 						> .mk-ui-header-search
 							display none
 
-.header[data-is-darkmode]
+.header[data-darkmode]
 	root(true)
 
-.header
+.header:not([data-darkmode])
 	root(false)
 
 </style>
diff --git a/src/client/app/desktop/views/components/widget-container.vue b/src/client/app/desktop/views/components/widget-container.vue
index 188a67313e..c3fac1399d 100644
--- a/src/client/app/desktop/views/components/widget-container.vue
+++ b/src/client/app/desktop/views/components/widget-container.vue
@@ -34,8 +34,8 @@ export default Vue.extend({
 </script>
 
 <style lang="stylus" scoped>
-.mk-widget-container
-	background #fff
+root(isDark)
+	background isDark ? #282C37 : #fff
 	border solid 1px rgba(0, 0, 0, 0.075)
 	border-radius 6px
 	overflow hidden
@@ -45,6 +45,8 @@ export default Vue.extend({
 		border none !important
 
 	> header
+		background isDark ? #313543 : #fff
+
 		> .title
 			z-index 1
 			margin 0
@@ -52,7 +54,7 @@ export default Vue.extend({
 			line-height 42px
 			font-size 0.9em
 			font-weight bold
-			color #888
+			color isDark ? #e3e5e8 : #888
 			box-shadow 0 1px rgba(0, 0, 0, 0.07)
 
 			> [data-fa]
@@ -70,16 +72,23 @@ export default Vue.extend({
 			width 42px
 			font-size 0.9em
 			line-height 42px
-			color #ccc
+			color isDark ? #9baec8 : #ccc
 
 			&:hover
-				color #aaa
+				color isDark ? #b2c1d5 : #aaa
 
 			&:active
-				color #999
+				color isDark ? #b2c1d5 : #999
 
 		&.withGradient
 			> .title
-				background linear-gradient(to bottom, #fff, #ececec)
+				background isDark ? linear-gradient(to bottom, #313543, #1d2027) : linear-gradient(to bottom, #fff, #ececec)
 				box-shadow 0 1px rgba(#000, 0.11)
+
+.mk-widget-container[data-darkmode]
+	root(true)
+
+.mk-widget-container:not([data-darkmode])
+	root(false)
+
 </style>
diff --git a/src/client/app/desktop/views/components/window.vue b/src/client/app/desktop/views/components/window.vue
index e2cab21799..3de1413ac4 100644
--- a/src/client/app/desktop/views/components/window.vue
+++ b/src/client/app/desktop/views/components/window.vue
@@ -465,7 +465,7 @@ export default Vue.extend({
 <style lang="stylus" scoped>
 @import '~const.styl'
 
-.mk-window
+root(isDark)
 	display block
 
 	> .bg
@@ -559,7 +559,7 @@ export default Vue.extend({
 		> .body
 			height 100%
 			overflow hidden
-			background #fff
+			background isDark ? #282C37 : #fff
 			border-radius 6px
 			box-shadow 0 2px 6px 0 rgba(0, 0, 0, 0.2)
 
@@ -571,12 +571,12 @@ export default Vue.extend({
 				overflow hidden
 				white-space nowrap
 				cursor move
-				background #fff
+				background isDark ? #313543 : #fff
 				border-radius 6px 6px 0 0
 				box-shadow 0 1px 0 rgba(#000, 0.1)
 
 				&.withGradient
-					background linear-gradient(to bottom, #fff, #ececec)
+					background isDark ? linear-gradient(to bottom, #313543, #1d2027) : linear-gradient(to bottom, #fff, #ececec)
 					box-shadow 0 1px 0 rgba(#000, 0.15)
 
 				&, *
@@ -593,7 +593,7 @@ export default Vue.extend({
 					font-size 1em
 					line-height $header-height
 					font-weight normal
-					color #666
+					color isDark ? #e3e5e8 : #666
 
 				> div:last-child
 					position absolute
@@ -608,16 +608,16 @@ export default Vue.extend({
 						padding 0
 						cursor pointer
 						font-size 1em
-						color rgba(#000, 0.4)
+						color isDark ? #9baec8 : rgba(#000, 0.4)
 						border none
 						outline none
 						background transparent
 
 						&:hover
-							color rgba(#000, 0.6)
+							color isDark ? #b2c1d5 : rgba(#000, 0.6)
 
 						&:active
-							color darken(#000, 30%)
+							color isDark ? #b2c1d5 : darken(#000, 30%)
 
 						> [data-fa]
 							padding 0
@@ -632,4 +632,10 @@ export default Vue.extend({
 		> .main > .body > .content
 			height calc(100% - 40px)
 
+.mk-window[data-darkmode]
+	root(true)
+
+.mk-window:not([data-darkmode])
+	root(false)
+
 </style>
diff --git a/src/client/app/init.css b/src/client/app/init.css
index 2587f63943..fa59195f71 100644
--- a/src/client/app/init.css
+++ b/src/client/app/init.css
@@ -56,6 +56,13 @@ body > noscript {
 			animation-delay: 0.32s;
 		}
 
+html[data-darkmode] #ini {
+	background: #191b22;
+}
+	html[data-darkmode] #ini > p {
+		color: #fff;
+	}
+
 @keyframes ini {
 	0%, 80%, 100% {
 		opacity: 1;