summaryrefslogtreecommitdiff
path: root/src/web
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-02-10 16:22:14 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-02-10 16:22:14 +0900
commit4f1795b97b43e324d47653c5b172afa984446868 (patch)
treec4dc6853e62297a284fa6bb9cbbdf4d7ab30d042 /src/web
parentwip (diff)
downloadmisskey-4f1795b97b43e324d47653c5b172afa984446868.tar.gz
misskey-4f1795b97b43e324d47653c5b172afa984446868.tar.bz2
misskey-4f1795b97b43e324d47653c5b172afa984446868.zip
wip
Diffstat (limited to 'src/web')
-rw-r--r--src/web/app/common/-tags/signin.tag155
-rw-r--r--src/web/app/common/-tags/signup.tag307
-rw-r--r--src/web/app/common/views/components/index.ts7
-rw-r--r--src/web/app/common/views/components/poll.vue (renamed from src/web/app/common/tags/poll.vue)0
-rw-r--r--src/web/app/common/views/components/reaction-icon.vue (renamed from src/web/app/common/tags/reaction-icon.vue)0
-rw-r--r--src/web/app/common/views/components/reaction-picker.vue (renamed from src/web/app/common/tags/reaction-picker.vue)0
-rw-r--r--src/web/app/common/views/components/reactions-viewer.vue (renamed from src/web/app/common/tags/reactions-viewer.vue)0
-rw-r--r--src/web/app/common/views/components/signin.vue138
-rw-r--r--src/web/app/common/views/components/signup.vue331
-rw-r--r--src/web/app/common/views/components/stream-indicator.vue (renamed from src/web/app/common/tags/stream-indicator.vue)0
-rw-r--r--src/web/app/common/views/components/time.vue (renamed from src/web/app/common/tags/time.vue)0
-rw-r--r--src/web/app/common/views/components/url-preview.vue (renamed from src/web/app/common/tags/url-preview.vue)0
-rw-r--r--src/web/app/common/views/components/url.vue (renamed from src/web/app/common/tags/url.vue)0
-rw-r--r--src/web/app/desktop/views/pages/welcome.vue158
-rw-r--r--src/web/app/init.ts2
15 files changed, 561 insertions, 537 deletions
diff --git a/src/web/app/common/-tags/signin.tag b/src/web/app/common/-tags/signin.tag
deleted file mode 100644
index 89213d1f73..0000000000
--- a/src/web/app/common/-tags/signin.tag
+++ /dev/null
@@ -1,155 +0,0 @@
-<mk-signin>
- <form :class="{ signing: signing }" onsubmit={ onsubmit }>
- <label class="user-name">
- <input ref="username" type="text" pattern="^[a-zA-Z0-9-]+$" placeholder="%i18n:common.tags.mk-signin.username%" autofocus="autofocus" required="required" oninput={ oninput }/>%fa:at%
- </label>
- <label class="password">
- <input ref="password" type="password" placeholder="%i18n:common.tags.mk-signin.password%" required="required"/>%fa:lock%
- </label>
- <label class="token" v-if="user && user.two_factor_enabled">
- <input ref="token" type="number" placeholder="%i18n:common.tags.mk-signin.token%" required="required"/>%fa:lock%
- </label>
- <button type="submit" disabled={ signing }>{ signing ? '%i18n:common.tags.mk-signin.signing-in%' : '%i18n:common.tags.mk-signin.signin%' }</button>
- </form>
- <style lang="stylus" scoped>
- :scope
- display block
-
- > form
- display block
- z-index 2
-
- &.signing
- &, *
- cursor wait !important
-
- label
- display block
- margin 12px 0
-
- [data-fa]
- 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
-
- input[type=text]
- input[type=password]
- input[type=number]
- 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
-
- &:hover
- background rgba(255, 255, 255, 0.7)
- border-color #ddd
-
- & + i
- color #797776
-
- &:focus
- background #fff
- border-color #ccc
-
- & + i
- color #797776
-
- [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
-
- &:hover
- color $theme-color
- transition all .2s ease
-
- &:focus
- color $theme-color
- transition all .2s ease
-
- &:active
- color darken($theme-color, 30%)
- transition all .2s ease
-
- &:disabled
- opacity 0.7
-
- </style>
- <script lang="typescript">
- this.mixin('api');
-
- this.user = null;
- this.signing = false;
-
- this.oninput = () => {
- this.api('users/show', {
- username: this.$refs.username.value
- }).then(user => {
- this.user = user;
- this.$emit('user', user);
- this.update();
- });
- };
-
- this.onsubmit = e => {
- e.preventDefault();
-
- if (this.$refs.username.value == '') {
- this.$refs.username.focus();
- return false;
- }
- if (this.$refs.password.value == '') {
- this.$refs.password.focus();
- return false;
- }
- if (this.user && this.user.two_factor_enabled && this.$refs.token.value == '') {
- this.$refs.token.focus();
- return false;
- }
-
- this.update({
- signing: true
- });
-
- this.api('signin', {
- username: this.$refs.username.value,
- password: this.$refs.password.value,
- token: this.user && this.user.two_factor_enabled ? this.$refs.token.value : undefined
- }).then(() => {
- location.reload();
- }).catch(() => {
- alert('something happened');
- this.update({
- signing: false
- });
- });
-
- return false;
- };
- </script>
-</mk-signin>
diff --git a/src/web/app/common/-tags/signup.tag b/src/web/app/common/-tags/signup.tag
deleted file mode 100644
index 99be10609b..0000000000
--- a/src/web/app/common/-tags/signup.tag
+++ /dev/null
@@ -1,307 +0,0 @@
-<mk-signup>
- <form onsubmit={ onsubmit } autocomplete="off">
- <label class="username">
- <p class="caption">%fa:at%%i18n:common.tags.mk-signup.username%</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" v-if="refs.username.value != '' && username-state != 'invalidFormat' && username-state != 'minRange' && username-state != 'maxRange'">{ _URL_ + '/' + refs.username.value }</p>
- <p class="info" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw%%i18n:common.tags.mk-signup.checking%</p>
- <p class="info" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.available%</p>
- <p class="info" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.unavailable%</p>
- <p class="info" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.error%</p>
- <p class="info" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.invalid-format%</p>
- <p class="info" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.too-short%</p>
- <p class="info" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.too-long%</p>
- </label>
- <label class="password">
- <p class="caption">%fa:lock%%i18n:common.tags.mk-signup.password%</p>
- <input ref="password" type="password" placeholder="%i18n:common.tags.mk-signup.password-placeholder%" autocomplete="off" required="required" onkeyup={ onChangePassword }/>
- <div class="meter" v-if="passwordStrength != ''" data-strength={ passwordStrength }>
- <div class="value" ref="passwordMetar"></div>
- </div>
- <p class="info" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.weak-password%</p>
- <p class="info" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.normal-password%</p>
- <p class="info" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.strong-password%</p>
- </label>
- <label class="retype-password">
- <p class="caption">%fa:lock%%i18n:common.tags.mk-signup.password%(%i18n:common.tags.mk-signup.retype%)</p>
- <input ref="passwordRetype" type="password" placeholder="%i18n:common.tags.mk-signup.retype-placeholder%" autocomplete="off" required="required" onkeyup={ onChangePasswordRetype }/>
- <p class="info" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.password-matched%</p>
- <p class="info" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.password-not-matched%</p>
- </label>
- <label class="recaptcha">
- <p class="caption"><template v-if="recaptchaed">%fa:toggle-on%</template><template v-if="!recaptchaed">%fa:toggle-off%</template>%i18n:common.tags.mk-signup.recaptcha%</p>
- <div v-if="recaptcha" class="g-recaptcha" data-callback="onRecaptchaed" data-expired-callback="onRecaptchaExpired" data-sitekey={ recaptcha.site_key }></div>
- </label>
- <label class="agree-tou">
- <input name="agree-tou" type="checkbox" autocomplete="off" required="required"/>
- <p><a href={ touUrl } target="_blank">利用規約</a>に同意する</p>
- </label>
- <button @click="onsubmit">%i18n:common.tags.mk-signup.create%</button>
- </form>
- <style lang="stylus" scoped>
- :scope
- display block
- min-width 302px
- overflow hidden
-
- > form
-
- label
- display block
- margin 16px 0
-
- > .caption
- margin 0 0 4px 0
- color #828888
- font-size 0.95em
-
- > [data-fa]
- margin-right 0.25em
- color #96adac
-
- > .info
- display block
- margin 4px 0
- font-size 0.8em
-
- > [data-fa]
- margin-right 0.3em
-
- &.username
- .profile-page-url-preview
- display block
- margin 4px 8px 0 4px
- font-size 0.8em
- color #888
-
- &:empty
- display none
-
- &:not(:empty) + .info
- margin-top 0
-
- &.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
- display block
- width 0%
- height 100%
- background transparent
- border-radius 4px
- transition all 0.1s ease
-
- [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
-
- &:hover
- border-color rgba(0, 0, 0, 0.2)
- transition all .1s ease
-
- &: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
-
- &:disabled
- opacity 0.5
-
- .agree-tou
- padding 4px
- border-radius 4px
-
- &: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 lang="typescript">
- this.mixin('api');
- const getPasswordStrength = require('syuilo-password-strength');
-
- this.usernameState = null;
- this.passwordStrength = '';
- this.passwordRetypeState = null;
- this.recaptchaed = false;
-
- this.aboutUrl = `${_DOCS_URL_}/${_LANG_}/tou`;
-
- window.onRecaptchaed = () => {
- this.recaptchaed = true;
- this.update();
- };
-
- window.onRecaptchaExpired = () => {
- this.recaptchaed = false;
- this.update();
- };
-
- this.on('mount', () => {
- this.update({
- recaptcha: {
- site_key: _RECAPTCHA_SITEKEY_
- }
- });
-
- const head = document.getElementsByTagName('head')[0];
- const script = document.createElement('script');
- script.setAttribute('src', 'https://www.google.com/recaptcha/api.js');
- head.appendChild(script);
- });
-
- this.onChangeUsername = () => {
- const username = this.$refs.username.value;
-
- if (username == '') {
- this.update({
- usernameState: null
- });
- return;
- }
-
- const err =
- !username.match(/^[a-zA-Z0-9\-]+$/) ? 'invalid-format' :
- username.length < 3 ? 'min-range' :
- username.length > 20 ? 'max-range' :
- null;
-
- if (err) {
- this.update({
- usernameState: err
- });
- return;
- }
-
- this.update({
- usernameState: 'wait'
- });
-
- this.api('username/available', {
- username: username
- }).then(result => {
- this.update({
- usernameState: result.available ? 'ok' : 'unavailable'
- });
- }).catch(err => {
- this.update({
- usernameState: 'error'
- });
- });
- };
-
- this.onChangePassword = () => {
- const password = this.$refs.password.value;
-
- if (password == '') {
- this.passwordStrength = '';
- return;
- }
-
- const strength = getPasswordStrength(password);
- this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low';
- this.update();
- this.$refs.passwordMetar.style.width = `${strength * 100}%`;
- };
-
- this.onChangePasswordRetype = () => {
- const password = this.$refs.password.value;
- const retypedPassword = this.$refs.passwordRetype.value;
-
- if (retypedPassword == '') {
- this.passwordRetypeState = null;
- return;
- }
-
- this.passwordRetypeState = password == retypedPassword ? 'match' : 'not-match';
- };
-
- this.onsubmit = e => {
- e.preventDefault();
-
- const username = this.$refs.username.value;
- const password = this.$refs.password.value;
-
- const locker = document.body.appendChild(document.createElement('mk-locker'));
-
- this.api('signup', {
- username: username,
- password: password,
- 'g-recaptcha-response': grecaptcha.getResponse()
- }).then(() => {
- this.api('signin', {
- username: username,
- password: password
- }).then(() => {
- location.href = '/';
- });
- }).catch(() => {
- alert('%i18n:common.tags.mk-signup.some-error%');
-
- grecaptcha.reset();
- this.recaptchaed = false;
-
- locker.parentNode.removeChild(locker);
- });
-
- return false;
- };
- </script>
-</mk-signup>
diff --git a/src/web/app/common/views/components/index.ts b/src/web/app/common/views/components/index.ts
new file mode 100644
index 0000000000..b1c5df8197
--- /dev/null
+++ b/src/web/app/common/views/components/index.ts
@@ -0,0 +1,7 @@
+import Vue from 'vue';
+
+import signin from './signin.vue';
+import signup from './signup.vue';
+
+Vue.component('mk-signin', signin);
+Vue.component('mk-signup', signup);
diff --git a/src/web/app/common/tags/poll.vue b/src/web/app/common/views/components/poll.vue
index d85caa00ce..d85caa00ce 100644
--- a/src/web/app/common/tags/poll.vue
+++ b/src/web/app/common/views/components/poll.vue
diff --git a/src/web/app/common/tags/reaction-icon.vue b/src/web/app/common/views/components/reaction-icon.vue
index 317daf0feb..317daf0feb 100644
--- a/src/web/app/common/tags/reaction-icon.vue
+++ b/src/web/app/common/views/components/reaction-icon.vue
diff --git a/src/web/app/common/tags/reaction-picker.vue b/src/web/app/common/views/components/reaction-picker.vue
index dd4d1380b7..dd4d1380b7 100644
--- a/src/web/app/common/tags/reaction-picker.vue
+++ b/src/web/app/common/views/components/reaction-picker.vue
diff --git a/src/web/app/common/tags/reactions-viewer.vue b/src/web/app/common/views/components/reactions-viewer.vue
index f6e37caa44..f6e37caa44 100644
--- a/src/web/app/common/tags/reactions-viewer.vue
+++ b/src/web/app/common/views/components/reactions-viewer.vue
diff --git a/src/web/app/common/views/components/signin.vue b/src/web/app/common/views/components/signin.vue
new file mode 100644
index 0000000000..5ffc518b3c
--- /dev/null
+++ b/src/web/app/common/views/components/signin.vue
@@ -0,0 +1,138 @@
+<template>
+<form class="form" :class="{ signing: signing }" @submit.prevent="onSubmit">
+ <label class="user-name">
+ <input v-model="username" type="text" pattern="^[a-zA-Z0-9-]+$" placeholder="%i18n:common.tags.mk-signin.username%" autofocus required @change="onUsernameChange"/>%fa:at%
+ </label>
+ <label class="password">
+ <input v-model="password" type="password" placeholder="%i18n:common.tags.mk-signin.password%" required/>%fa:lock%
+ </label>
+ <label class="token" v-if="user && user.two_factor_enabled">
+ <input v-model="token" type="number" placeholder="%i18n:common.tags.mk-signin.token%" required/>%fa:lock%
+ </label>
+ <button type="submit" disabled={ signing }>{ signing ? '%i18n:common.tags.mk-signin.signing-in%' : '%i18n:common.tags.mk-signin.signin%' }</button>
+</form>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+
+export default Vue.extend({
+ props: ['os'],
+ data() {
+ return {
+ signing: false,
+ user: null
+ };
+ },
+ methods: {
+ onUsernameChange() {
+ this.os.api('users/show', {
+ username: this.username
+ }).then(user => {
+ this.user = user;
+ });
+ },
+ onSubmit() {
+ this.signing = true;
+
+ this.os.api('signin', {
+ username: this.username,
+ password: this.password,
+ token: this.user && this.user.two_factor_enabled ? this.token : undefined
+ }).then(() => {
+ location.reload();
+ }).catch(() => {
+ alert('something happened');
+ this.signing = false;
+ });
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.form
+ display block
+ z-index 2
+
+ &.signing
+ &, *
+ cursor wait !important
+
+ label
+ display block
+ margin 12px 0
+
+ [data-fa]
+ 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
+
+ input[type=text]
+ input[type=password]
+ input[type=number]
+ 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
+
+ &:hover
+ background rgba(255, 255, 255, 0.7)
+ border-color #ddd
+
+ & + i
+ color #797776
+
+ &:focus
+ background #fff
+ border-color #ccc
+
+ & + i
+ color #797776
+
+ [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
+
+ &:hover
+ color $theme-color
+ transition all .2s ease
+
+ &:focus
+ color $theme-color
+ transition all .2s ease
+
+ &:active
+ color darken($theme-color, 30%)
+ transition all .2s ease
+
+ &:disabled
+ opacity 0.7
+
+</style>
diff --git a/src/web/app/common/views/components/signup.vue b/src/web/app/common/views/components/signup.vue
new file mode 100644
index 0000000000..1734f77316
--- /dev/null
+++ b/src/web/app/common/views/components/signup.vue
@@ -0,0 +1,331 @@
+<template>
+<form @submit.prevent="onSubmit" autocomplete="off">
+ <label class="username">
+ <p class="caption">%fa:at%%i18n:common.tags.mk-signup.username%</p>
+ <input v-model="username" type="text" pattern="^[a-zA-Z0-9-]{3,20}$" placeholder="a~z、A~Z、0~9、-" autocomplete="off" required @keyup="onChangeUsername"/>
+ <p class="profile-page-url-preview" v-if="refs.username.value != '' && username-state != 'invalidFormat' && username-state != 'minRange' && username-state != 'maxRange'">{ _URL_ + '/' + refs.username.value }</p>
+ <p class="info" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw%%i18n:common.tags.mk-signup.checking%</p>
+ <p class="info" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.available%</p>
+ <p class="info" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.unavailable%</p>
+ <p class="info" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.error%</p>
+ <p class="info" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.invalid-format%</p>
+ <p class="info" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.too-short%</p>
+ <p class="info" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.too-long%</p>
+ </label>
+ <label class="password">
+ <p class="caption">%fa:lock%%i18n:common.tags.mk-signup.password%</p>
+ <input v-model="password" type="password" placeholder="%i18n:common.tags.mk-signup.password-placeholder%" autocomplete="off" required @keyup="onChangePassword"/>
+ <div class="meter" v-if="passwordStrength != ''" :data-strength="passwordStrength">
+ <div class="value" ref="passwordMetar"></div>
+ </div>
+ <p class="info" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.weak-password%</p>
+ <p class="info" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.normal-password%</p>
+ <p class="info" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.strong-password%</p>
+ </label>
+ <label class="retype-password">
+ <p class="caption">%fa:lock%%i18n:common.tags.mk-signup.password%(%i18n:common.tags.mk-signup.retype%)</p>
+ <input v-model="passwordRetype" type="password" placeholder="%i18n:common.tags.mk-signup.retype-placeholder%" autocomplete="off" required @keyup="onChangePasswordRetype"/>
+ <p class="info" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.password-matched%</p>
+ <p class="info" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.password-not-matched%</p>
+ </label>
+ <label class="recaptcha">
+ <p class="caption"><template v-if="recaptchaed">%fa:toggle-on%</template><template v-if="!recaptchaed">%fa:toggle-off%</template>%i18n:common.tags.mk-signup.recaptcha%</p>
+ <div v-if="recaptcha" class="g-recaptcha" data-callback="onRecaptchaed" data-expired-callback="onRecaptchaExpired" data-sitekey="recaptcha.site_key"></div>
+ </label>
+ <label class="agree-tou">
+ <input name="agree-tou" type="checkbox" autocomplete="off" required/>
+ <p><a :href="touUrl" target="_blank">利用規約</a>に同意する</p>
+ </label>
+ <button type="submit">%i18n:common.tags.mk-signup.create%</button>
+</form>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+const getPasswordStrength = require('syuilo-password-strength');
+import
+
+const aboutUrl = `${_DOCS_URL_}/${_LANG_}/tou`;
+
+export default Vue.extend({
+ methods: {
+ onSubmit() {
+
+ }
+ },
+ mounted() {
+ const head = document.getElementsByTagName('head')[0];
+ const script = document.createElement('script');
+ script.setAttribute('src', 'https://www.google.com/recaptcha/api.js');
+ head.appendChild(script);
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+ :scope
+ display block
+ min-width 302px
+ overflow hidden
+
+ > form
+
+ label
+ display block
+ margin 16px 0
+
+ > .caption
+ margin 0 0 4px 0
+ color #828888
+ font-size 0.95em
+
+ > [data-fa]
+ margin-right 0.25em
+ color #96adac
+
+ > .info
+ display block
+ margin 4px 0
+ font-size 0.8em
+
+ > [data-fa]
+ margin-right 0.3em
+
+ &.username
+ .profile-page-url-preview
+ display block
+ margin 4px 8px 0 4px
+ font-size 0.8em
+ color #888
+
+ &:empty
+ display none
+
+ &:not(:empty) + .info
+ margin-top 0
+
+ &.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
+ display block
+ width 0%
+ height 100%
+ background transparent
+ border-radius 4px
+ transition all 0.1s ease
+
+ [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
+
+ &:hover
+ border-color rgba(0, 0, 0, 0.2)
+ transition all .1s ease
+
+ &: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
+
+ &:disabled
+ opacity 0.5
+
+ .agree-tou
+ padding 4px
+ border-radius 4px
+
+ &: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 lang="typescript">
+ this.mixin('api');
+
+
+ this.usernameState = null;
+ this.passwordStrength = '';
+ this.passwordRetypeState = null;
+ this.recaptchaed = false;
+
+ this.aboutUrl = `${_DOCS_URL_}/${_LANG_}/tou`;
+
+ window.onRecaptchaed = () => {
+ this.recaptchaed = true;
+ this.update();
+ };
+
+ window.onRecaptchaExpired = () => {
+ this.recaptchaed = false;
+ this.update();
+ };
+
+ this.on('mount', () => {
+ this.update({
+ recaptcha: {
+ site_key: _RECAPTCHA_SITEKEY_
+ }
+ });
+
+ const head = document.getElementsByTagName('head')[0];
+ const script = document.createElement('script');
+ script.setAttribute('src', 'https://www.google.com/recaptcha/api.js');
+ head.appendChild(script);
+ });
+
+ this.onChangeUsername = () => {
+ const username = this.$refs.username.value;
+
+ if (username == '') {
+ this.update({
+ usernameState: null
+ });
+ return;
+ }
+
+ const err =
+ !username.match(/^[a-zA-Z0-9\-]+$/) ? 'invalid-format' :
+ username.length < 3 ? 'min-range' :
+ username.length > 20 ? 'max-range' :
+ null;
+
+ if (err) {
+ this.update({
+ usernameState: err
+ });
+ return;
+ }
+
+ this.update({
+ usernameState: 'wait'
+ });
+
+ this.api('username/available', {
+ username: username
+ }).then(result => {
+ this.update({
+ usernameState: result.available ? 'ok' : 'unavailable'
+ });
+ }).catch(err => {
+ this.update({
+ usernameState: 'error'
+ });
+ });
+ };
+
+ this.onChangePassword = () => {
+ const password = this.$refs.password.value;
+
+ if (password == '') {
+ this.passwordStrength = '';
+ return;
+ }
+
+ const strength = getPasswordStrength(password);
+ this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low';
+ this.update();
+ this.$refs.passwordMetar.style.width = `${strength * 100}%`;
+ };
+
+ this.onChangePasswordRetype = () => {
+ const password = this.$refs.password.value;
+ const retypedPassword = this.$refs.passwordRetype.value;
+
+ if (retypedPassword == '') {
+ this.passwordRetypeState = null;
+ return;
+ }
+
+ this.passwordRetypeState = password == retypedPassword ? 'match' : 'not-match';
+ };
+
+ this.onsubmit = e => {
+ e.preventDefault();
+
+ const username = this.$refs.username.value;
+ const password = this.$refs.password.value;
+
+ const locker = document.body.appendChild(document.createElement('mk-locker'));
+
+ this.api('signup', {
+ username: username,
+ password: password,
+ 'g-recaptcha-response': grecaptcha.getResponse()
+ }).then(() => {
+ this.api('signin', {
+ username: username,
+ password: password
+ }).then(() => {
+ location.href = '/';
+ });
+ }).catch(() => {
+ alert('%i18n:common.tags.mk-signup.some-error%');
+
+ grecaptcha.reset();
+ this.recaptchaed = false;
+
+ locker.parentNode.removeChild(locker);
+ });
+
+ return false;
+ };
+</script>
diff --git a/src/web/app/common/tags/stream-indicator.vue b/src/web/app/common/views/components/stream-indicator.vue
index 0721c77ad7..0721c77ad7 100644
--- a/src/web/app/common/tags/stream-indicator.vue
+++ b/src/web/app/common/views/components/stream-indicator.vue
diff --git a/src/web/app/common/tags/time.vue b/src/web/app/common/views/components/time.vue
index 7d165fc006..7d165fc006 100644
--- a/src/web/app/common/tags/time.vue
+++ b/src/web/app/common/views/components/time.vue
diff --git a/src/web/app/common/tags/url-preview.vue b/src/web/app/common/views/components/url-preview.vue
index 88158db845..88158db845 100644
--- a/src/web/app/common/tags/url-preview.vue
+++ b/src/web/app/common/views/components/url-preview.vue
diff --git a/src/web/app/common/tags/url.vue b/src/web/app/common/views/components/url.vue
index 4cc76f7e24..4cc76f7e24 100644
--- a/src/web/app/common/tags/url.vue
+++ b/src/web/app/common/views/components/url.vue
diff --git a/src/web/app/desktop/views/pages/welcome.vue b/src/web/app/desktop/views/pages/welcome.vue
index c0e1c0bd4f..68b5f4cc98 100644
--- a/src/web/app/desktop/views/pages/welcome.vue
+++ b/src/web/app/desktop/views/pages/welcome.vue
@@ -17,105 +17,113 @@
<p class="c">{ _COPYRIGHT_ }</p>
</div>
</footer>
+ <modal name="signup">
+ <mk-signup/>
+ </modal>
</div>
</template>
-<style>
- #wait {
- right: auto;
- left: 15px;
+<script lang="ts">
+import Vue from 'vue';
+
+export default Vue.extend({
+ methods: {
+ signup() {
+ this.$modal.show('signup');
+ }
}
+});
+</script>
+
+<style>
+#wait {
+ right: auto;
+ left: 15px;
+}
</style>
<style lang="stylus" scoped>
- .root
+.root
+ display flex
+ flex-direction column
+ flex 1
+ background #eee
+ $width = 1000px
+
+ > main
display flex
- flex-direction column
flex 1
- background #eee
- $width = 1000px
-
- > main
- display flex
- flex 1
- max-width $width
- margin 0 auto
- padding 80px 0 0 0
+ max-width $width
+ margin 0 auto
+ padding 80px 0 0 0
- > div:first-child
- margin 0 auto 0 0
- width calc(100% - 500px)
- color #777
+ > div:first-child
+ margin 0 auto 0 0
+ width calc(100% - 500px)
+ color #777
- > h1
- margin 0
- font-weight normal
- font-variant small-caps
- letter-spacing 12px
+ > h1
+ margin 0
+ font-weight normal
+ font-variant small-caps
+ letter-spacing 12px
- > p
- margin 0.5em 0
- line-height 2em
+ > p
+ margin 0.5em 0
+ line-height 2em
- button
- padding 8px 16px
- font-size inherit
+ button
+ padding 8px 16px
+ font-size inherit
- .signup
- color $theme-color
- border solid 2px $theme-color
- border-radius 4px
+ .signup
+ color $theme-color
+ border solid 2px $theme-color
+ border-radius 4px
- &:focus
- box-shadow 0 0 0 3px rgba($theme-color, 0.2)
+ &:focus
+ box-shadow 0 0 0 3px rgba($theme-color, 0.2)
- &:hover
- color $theme-color-foreground
- background $theme-color
+ &:hover
+ color $theme-color-foreground
+ background $theme-color
- &:active
- color $theme-color-foreground
- background darken($theme-color, 10%)
- border-color darken($theme-color, 10%)
+ &:active
+ color $theme-color-foreground
+ background darken($theme-color, 10%)
+ border-color darken($theme-color, 10%)
- .signin
- &:focus
- color #444
+ .signin
+ &:focus
+ color #444
- &:hover
- color #444
+ &:hover
+ color #444
- &:active
- color #333
+ &:active
+ color #333
- > div:last-child
- margin 0 0 0 auto
+ > div:last-child
+ margin 0 0 0 auto
- > footer
- background #fff
+ > footer
+ background #fff
- *
- color #fff !important
- text-shadow 0 0 8px #000
- font-weight bold
+ *
+ color #fff !important
+ text-shadow 0 0 8px #000
+ font-weight bold
- > div
- max-width $width
- margin 0 auto
- padding 16px 0
- text-align center
- border-top solid 1px #fff
+ > div
+ max-width $width
+ margin 0 auto
+ padding 16px 0
+ text-align center
+ border-top solid 1px #fff
- > .c
- margin 0
- line-height 64px
- font-size 10px
+ > .c
+ margin 0
+ line-height 64px
+ font-size 10px
</style>
-
-<script lang="ts">
-import Vue from 'vue'
-export default Vue.extend({
-
-})
-</script>
diff --git a/src/web/app/init.ts b/src/web/app/init.ts
index 796a966940..20ea1df8b2 100644
--- a/src/web/app/init.ts
+++ b/src/web/app/init.ts
@@ -9,8 +9,10 @@ declare const _HOST_: string;
import Vue from 'vue';
import VueRouter from 'vue-router';
+import VModal from 'vue-js-modal';
Vue.use(VueRouter);
+Vue.use(VModal);
import App from './app.vue';