From 66f3a155e6050fc297d2f600e6d619c5dba0f764 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 3 Sep 2018 23:23:50 +0900
Subject: [PATCH] =?UTF-8?q?=E3=81=AA=E3=82=93=E3=81=8B=E3=82=82=E3=81=86?=
 =?UTF-8?q?=E3=82=81=E3=81=A3=E3=81=A1=E3=82=83=E3=82=84=E3=81=A3=E3=81=9F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../app/common/views/components/signin.vue    |   2 +-
 .../app/common/views/widgets/broadcast.vue    |  10 +-
 .../views/pages/admin/admin.announcements.vue |  41 +++
 .../app/desktop/views/pages/admin/admin.vue   |   6 +
 .../app/desktop/views/pages/welcome.vue       | 297 ++++++++----------
 src/server/api/endpoints/admin/update-meta.ts |  12 +-
 6 files changed, 199 insertions(+), 169 deletions(-)
 create mode 100644 src/client/app/desktop/views/pages/admin/admin.announcements.vue

diff --git a/src/client/app/common/views/components/signin.vue b/src/client/app/common/views/components/signin.vue
index 5230ac371a..b1c6782e93 100644
--- a/src/client/app/common/views/components/signin.vue
+++ b/src/client/app/common/views/components/signin.vue
@@ -78,7 +78,7 @@ export default Vue.extend({
 			cursor wait !important
 
 	> .avatar
-		margin 16px auto 0 auto
+		margin 0 auto 0 auto
 		width 64px
 		height 64px
 		background #ddd
diff --git a/src/client/app/common/views/widgets/broadcast.vue b/src/client/app/common/views/widgets/broadcast.vue
index 69b2a54fe9..d3a39bd9cc 100644
--- a/src/client/app/common/views/widgets/broadcast.vue
+++ b/src/client/app/common/views/widgets/broadcast.vue
@@ -42,15 +42,7 @@ export default define({
 	},
 	mounted() {
 		(this as any).os.getMeta().then(meta => {
-			let broadcasts = [];
-			if (meta.broadcasts) {
-				meta.broadcasts.forEach(broadcast => {
-					if (broadcast[lang]) {
-						broadcasts.push(broadcast[lang]);
-					}
-				});
-			}
-			this.broadcasts = broadcasts;
+			this.broadcasts = meta.broadcasts;
 			this.fetching = false;
 		});
 	},
diff --git a/src/client/app/desktop/views/pages/admin/admin.announcements.vue b/src/client/app/desktop/views/pages/admin/admin.announcements.vue
new file mode 100644
index 0000000000..532400deb2
--- /dev/null
+++ b/src/client/app/desktop/views/pages/admin/admin.announcements.vue
@@ -0,0 +1,41 @@
+<template>
+<div class="qldxjjsrseehkusjuoooapmsprvfrxyl mk-admin-card">
+	<header>%i18n:@announcements%</header>
+	<textarea v-model="broadcasts"></textarea>
+	<button class="ui" @click="save">%i18n:@save%</button>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from "vue";
+
+export default Vue.extend({
+	data() {
+		return {
+			broadcasts: '',
+		};
+	},
+	created() {
+		(this as any).os.getMeta().then(meta => {
+			this.broadcasts = JSON.stringify(meta.broadcasts, null, '  ');
+		});
+	},
+	methods: {
+		save() {
+			(this as any).api('admin/update-meta', {
+				broadcasts: JSON.parse(this.broadcasts)
+			});
+		}
+	}
+});
+</script>
+
+<style lang="stylus" scoped>
+@import '~const.styl'
+
+.qldxjjsrseehkusjuoooapmsprvfrxyl
+	textarea
+		width 100%
+		min-height 300px
+
+</style>
diff --git a/src/client/app/desktop/views/pages/admin/admin.vue b/src/client/app/desktop/views/pages/admin/admin.vue
index 3438462cd6..a71059c378 100644
--- a/src/client/app/desktop/views/pages/admin/admin.vue
+++ b/src/client/app/desktop/views/pages/admin/admin.vue
@@ -4,6 +4,7 @@
 		<ul>
 			<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:chalkboard .fw%%i18n:@dashboard%</li>
 			<li @click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li>
+			<li @click="nav('announcements')" :class="{ active: page == 'announcements' }">%fa:broadcast-tower .fw%%i18n:@announcements%</li>
 			<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:@drive%</li> -->
 			<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> -->
 		</ul>
@@ -13,6 +14,9 @@
 			<x-dashboard/>
 			<x-charts/>
 		</div>
+		<div v-show="page == 'announcements'">
+			<x-announcements/>
+		</div>
 		<div v-if="page == 'users'">
 			<x-suspend-user/>
 			<x-unsuspend-user/>
@@ -28,6 +32,7 @@
 <script lang="ts">
 import Vue from "vue";
 import XDashboard from "./admin.dashboard.vue";
+import XAnnouncements from "./admin.announcements.vue";
 import XSuspendUser from "./admin.suspend-user.vue";
 import XUnsuspendUser from "./admin.unsuspend-user.vue";
 import XVerifyUser from "./admin.verify-user.vue";
@@ -37,6 +42,7 @@ import XCharts from "../../components/charts.vue";
 export default Vue.extend({
 	components: {
 		XDashboard,
+		XAnnouncements,
 		XSuspendUser,
 		XUnsuspendUser,
 		XVerifyUser,
diff --git a/src/client/app/desktop/views/pages/welcome.vue b/src/client/app/desktop/views/pages/welcome.vue
index ae9bf7e678..e67ef16136 100644
--- a/src/client/app/desktop/views/pages/welcome.vue
+++ b/src/client/app/desktop/views/pages/welcome.vue
@@ -1,46 +1,60 @@
 <template>
 <div class="mk-welcome">
-	<img ref="pointer" class="pointer" src="/assets/pointer.png" alt="">
 	<button @click="dark">
 		<template v-if="$store.state.device.darkmode">%fa:moon%</template>
 		<template v-else>%fa:R moon%</template>
 	</button>
+
+	<mk-forkit class="forkit"/>
+
 	<div class="body">
-		<div class="container">
+		<div class="main">
+			<h1 v-if="name != 'Misskey'">{{ name }}</h1>
+			<h1 v-else><img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" :alt="name"></h1>
+
 			<div class="info">
-				<span><b>{{ host }}</b></span>
+				<span><b>{{ host }}</b> - <span v-html="'%i18n:@powered-by-misskey%'"></span></span>
 				<span class="stats" v-if="stats">
 					<span>%fa:user% {{ stats.originalUsersCount | number }}</span>
 					<span>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</span>
 				</span>
 			</div>
-			<main>
-				<div class="about">
-					<h1 v-if="name != 'Misskey'">{{ name }}</h1>
-					<h1 v-else><img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" :alt="name"></h1>
-					<p class="powerd-by" v-if="name != 'Misskey'" v-html="'%i18n:@powered-by-misskey%'"></p>
-					<p class="desc" v-html="description || '%i18n:common.about%'"></p>
-					<a ref="signup" @click="signup">πŸ“¦ %i18n:@signup%</a>
-				</div>
-				<div class="login">
-					<mk-signin/>
-				</div>
-			</main>
+
+			<p class="desc" v-html="description || '%i18n:common.about%'"></p>
+
+			<p class="sign">
+				<span class="signup" @click="signup">%i18n:@signup%</span>
+				<span class="divider">|</span>
+				<span class="signin" @click="signin">%i18n:@signin%</span>
+			</p>
+
 			<div class="hashtags">
 				<router-link v-for="tag in tags" :key="tag" :to="`/tags/${ tag }`" :title="tag">#{{ tag }}</router-link>
 			</div>
+		</div>
+
+		<div class="broadcasts">
+			<div v-for="broadcast in broadcasts">
+				<h1 v-html="broadcast.title"></h1>
+				<div v-html="broadcast.text"></div>
+			</div>
+		</div>
+
+		<div class="nav">
 			<mk-nav class="nav"/>
 		</div>
-		<mk-forkit class="forkit"/>
-		<img src="assets/title.dark.svg" :alt="name">
-	</div>
-	<div class="tl">
-		<mk-welcome-timeline :max="20"/>
+
+		<mk-welcome-timeline class="tl" :max="20"/>
 	</div>
 
-	<modal name="signup" width="500px" height="auto" scrollable>
-		<header :class="$style.signupFormHeader">%i18n:@signup%</header>
-		<mk-signup :class="$style.signupForm"/>
+	<modal name="signup" :class="$store.state.device.darkmode ? 'modal-dark' : 'modal-light'" width="450px" height="auto" scrollable>
+		<header class="formHeader">%i18n:@signup%</header>
+		<mk-signup class="form"/>
+	</modal>
+
+	<modal name="signin" :class="$store.state.device.darkmode ? 'modal-dark' : 'modal-light'" width="450px" height="auto" scrollable>
+		<header class="formHeader">%i18n:@signin%</header>
+		<mk-signin class="form"/>
 	</modal>
 </div>
 </template>
@@ -57,7 +71,7 @@ export default Vue.extend({
 			host,
 			name: 'Misskey',
 			description: '',
-			pointerInterval: null,
+			broadcasts: [],
 			tags: []
 		};
 	},
@@ -65,6 +79,7 @@ export default Vue.extend({
 		(this as any).os.getMeta().then(meta => {
 			this.name = meta.name;
 			this.description = meta.description;
+			this.broadcasts = meta.broadcasts;
 		});
 
 		(this as any).api('stats').then(stats => {
@@ -75,19 +90,7 @@ export default Vue.extend({
 			this.tags = stats.map(x => x.tag);
 		});
 	},
-	mounted() {
-		this.point();
-		this.pointerInterval = setInterval(this.point, 100);
-	},
-	beforeDestroy() {
-		clearInterval(this.pointerInterval);
-	},
 	methods: {
-		point() {
-			const x = this.$refs.signup.getBoundingClientRect();
-			this.$refs.pointer.style.top = x.top + x.height + 'px';
-			this.$refs.pointer.style.left = x.left + 'px';
-		},
 		signup() {
 			this.$modal.show('signup');
 		},
@@ -104,11 +107,40 @@ export default Vue.extend({
 });
 </script>
 
-<style>
-#wait {
-	right: auto;
-	left: 15px;
-}
+<style lang="stylus">
+#wait
+	right auto
+	left 15px
+
+.v--modal-overlay
+	background rgba(0, 0, 0, 0.4)
+
+.modal-light
+	.v--modal-box
+		color #777
+
+		.formHeader
+			border-bottom solid 1px #eee
+
+.modal-dark
+	.v--modal-box
+		background #313543
+		color #fff
+
+		.formHeader
+			border-bottom solid 1px rgba(#000, 0.2)
+
+.modal-light
+.modal-dark
+	.form
+		padding 24px 48px 48px 48px
+
+	.formHeader
+		text-align center
+		padding 48px 0 12px 0
+		margin 0 48px
+		font-size 1.5em
+
 </style>
 
 <style lang="stylus" scoped>
@@ -117,122 +149,85 @@ export default Vue.extend({
 root(isDark)
 	display flex
 	min-height 100vh
+	//background-color #00070F
+	//background-image url('/assets/bg.jpg')
+	//background-position center
+	//background-size cover
 
-	> .pointer
-		display block
+	> .forkit
 		position absolute
-		z-index 1
 		top 0
 		right 0
-		width 180px
-		margin 0 0 0 -180px
-		transform rotateY(180deg) translateX(-10px) translateY(-48px)
-		pointer-events none
 
 	> button
 		position fixed
 		z-index 1
-		top 0
-		left 0
+		bottom 64px
+		left 64px
 		padding 16px
 		font-size 18px
-		color #fff
-
-		display none // TODO
+		color isDark ? #fff : #444
 
 	> .body
-		flex 1
-		padding 64px 0 0 0
-		text-align center
-		background #578394
-		background-position center
-		background-size cover
+		display grid
+		grid-template-rows 0.5fr 0.5fr 64px
+		grid-template-columns 1fr 350px
+		gap 16px
+		width 100%
+		max-width 1200px
+		height 100vh
+		margin 0 auto
+		padding 64px
 
-		&:before
-			content ''
-			display block
-			position absolute
-			top 0
-			left 0
-			right 0
-			bottom 0
-			background rgba(#000, 0.5)
+		> *
+			color isDark ? #fff : #444
+			background isDark ? #313543 : #fff
+			box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
+			//border-radius 8px
+			overflow auto
 
-		> .forkit
-			position absolute
-			top 0
-			right 0
+		> .main
+			grid-row 1
+			grid-column 1
+			padding 32px
 
-		> img
-			position absolute
-			bottom 16px
-			right 16px
-			width 150px
+			> h1
+				margin 0
 
-		> .container
-			$aboutWidth = 380px
-			$loginWidth = 340px
-			$width = $aboutWidth + $loginWidth
+				> img
+					margin -8px 0 0 -16px
+					max-width 280px
 
 			> .info
 				margin 0 auto 16px auto
 				width $width
 				font-size 14px
-				color #fff
 
 				> .stats
 					margin-left 16px
 					padding-left 16px
-					border-left solid 1px #fff
+					border-left solid 1px isDark ? #fff : #444
 
 					> *
 						margin-right 16px
 
-			> main
-				display flex
-				margin auto
-				width $width
-				border-radius 8px
-				overflow hidden
-				box-shadow 0 2px 8px rgba(#000, 0.3)
+			> .sign
+				font-size 120%
 
-				> .about
-					width $aboutWidth
-					color #444
-					background #fff
+				> .divider
+					margin 0 16px
 
-					> h1
-						margin 0 0 16px 0
-						padding 32px 32px 0 32px
-						color #444
+				> .signin
+				> .signup
+					cursor pointer
 
-						> img
-							width 170px
-							vertical-align bottom
-
-					> .powerd-by
-						margin 16px
-						opacity 0.7
-
-					> .desc
-						margin 0
-						padding 0 32px 16px 32px
-
-					> a
-						display inline-block
-						margin 0 0 32px 0
-						font-weight bold
-
-				> .login
-					width $loginWidth
-					padding 16px 32px 32px 32px
-					background isDark ? #2e3440 : #f5f5f5
+					&:hover
+						color $theme-color
 
 			> .hashtags
 				margin 16px auto
 				width $width
 				font-size 14px
-				color #fff
 				background rgba(#000, 0.3)
 				border-radius 8px
 
@@ -240,20 +235,32 @@ root(isDark)
 					display inline-block
 					margin 14px
 
-			> .nav
-				display block
-				margin 16px 0
-				font-size 14px
-				color #fff
+		> .broadcasts
+			grid-row 2
+			grid-column 1
+			padding 32px
 
-	> .tl
-		margin 0
-		width 410px
-		height 100vh
-		text-align left
-		background isDark ? #313543 : #fff
+			> div
+				padding 0 0 16px 0
+				margin 0 0 16px 0
+				border-bottom 1px solid isDark ? rgba(#000, 0.2) : rgba(#000, 0.05)
 
-		> *
+				> h1
+					margin 0
+					font-size 1.5em
+
+		> .nav
+			display flex
+			justify-content center
+			align-items center
+			grid-row 3
+			grid-column 1
+			font-size 14px
+
+		> .tl
+			grid-row 1 / 4
+			grid-column 2
+			text-align left
 			max-height 100%
 			overflow auto
 
@@ -264,29 +271,3 @@ root(isDark)
 	root(false)
 
 </style>
-
-<style lang="stylus" module>
-.signupForm
-	padding 24px 48px 48px 48px
-
-.signupFormHeader
-	padding 48px 0 12px 0
-	margin: 0 48px
-	font-size 1.5em
-	color #777
-	border-bottom solid 1px #eee
-
-.signinForm
-	padding 24px 48px 48px 48px
-
-.signinFormHeader
-	padding 48px 0 12px 0
-	margin: 0 48px
-	font-size 1.5em
-	color #777
-	border-bottom solid 1px #eee
-
-.nav
-	a
-		color #666
-</style>
diff --git a/src/server/api/endpoints/admin/update-meta.ts b/src/server/api/endpoints/admin/update-meta.ts
index 9737a281ed..10ca15d329 100644
--- a/src/server/api/endpoints/admin/update-meta.ts
+++ b/src/server/api/endpoints/admin/update-meta.ts
@@ -11,11 +11,17 @@ export const meta = {
 	requireAdmin: true,
 
 	params: {
+		broadcasts: $.arr($.obj()).optional.nullable.note({
+			desc: {
+				'ja-JP': 'γƒ–γƒ­γƒΌγƒ‰γ‚­γƒ£γ‚Ήγƒˆ'
+			}
+		}),
+
 		disableRegistration: $.bool.optional.nullable.note({
 			desc: {
 				'ja-JP': 'ζ‹›εΎ…εˆΆγ‹ε¦γ‹'
 			}
-		}),
+		})
 	}
 };
 
@@ -25,6 +31,10 @@ export default (params: any) => new Promise(async (res, rej) => {
 
 	const set = {} as any;
 
+	if (ps.broadcasts) {
+		set.broadcasts = ps.broadcasts;
+	}
+
 	if (typeof ps.disableRegistration === 'boolean') {
 		set.disableRegistration = ps.disableRegistration;
 	}