diff options
| author | syuilo <syuilotan@yahoo.co.jp> | 2018-02-10 17:01:32 +0900 |
|---|---|---|
| committer | syuilo <syuilotan@yahoo.co.jp> | 2018-02-10 17:01:32 +0900 |
| commit | c869883d76455844e8d56ec4e863c6405489f897 (patch) | |
| tree | e5dfbe0b10cf5b208a2d008d3bd51c3e7675e258 | |
| parent | wip (diff) | |
| download | sharkey-c869883d76455844e8d56ec4e863c6405489f897.tar.gz sharkey-c869883d76455844e8d56ec4e863c6405489f897.tar.bz2 sharkey-c869883d76455844e8d56ec4e863c6405489f897.zip | |
wip
| -rw-r--r-- | src/web/app/common/views/components/signin.vue | 2 | ||||
| -rw-r--r-- | src/web/app/common/views/components/signup.vue | 434 | ||||
| -rw-r--r-- | src/web/app/config.ts | 11 | ||||
| -rw-r--r-- | src/web/app/desktop/views/pages/welcome.vue | 2 | ||||
| -rw-r--r-- | src/web/app/init.ts | 3 | ||||
| -rw-r--r-- | webpack/module/rules/fa.ts | 2 | ||||
| -rw-r--r-- | webpack/module/rules/i18n.ts | 2 |
7 files changed, 208 insertions, 248 deletions
diff --git a/src/web/app/common/views/components/signin.vue b/src/web/app/common/views/components/signin.vue index 5ffc518b3c..ee26110a43 100644 --- a/src/web/app/common/views/components/signin.vue +++ b/src/web/app/common/views/components/signin.vue @@ -13,7 +13,7 @@ </form> </template> -<script lang="ts"> +<script> import Vue from 'vue'; export default Vue.extend({ diff --git a/src/web/app/common/views/components/signup.vue b/src/web/app/common/views/components/signup.vue index 1734f77316..723555cdc4 100644 --- a/src/web/app/common/views/components/signup.vue +++ b/src/web/app/common/views/components/signup.vue @@ -1,9 +1,9 @@ <template> -<form @submit.prevent="onSubmit" autocomplete="off"> +<form class="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="profile-page-url-preview" v-if="username != '' && 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> @@ -30,7 +30,7 @@ </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> + <div v-if="recaptcha" class="g-recaptcha" data-callback="onRecaptchaed" data-expired-callback="onRecaptchaExpired" :data-sitekey="recaptchaSitekey"></div> </label> <label class="agree-tou"> <input name="agree-tou" type="checkbox" autocomplete="off" required/> @@ -43,16 +43,98 @@ <script lang="ts"> import Vue from 'vue'; const getPasswordStrength = require('syuilo-password-strength'); -import - -const aboutUrl = `${_DOCS_URL_}/${_LANG_}/tou`; +import { docsUrl, lang, recaptchaSitekey } from '../../../config'; export default Vue.extend({ + props: ['os'], + data() { + return { + username: '', + password: '', + retypedPassword: '', + touUrl: `${docsUrl}/${lang}/tou`, + recaptchaSitekey, + recaptchaed: false, + usernameState: null, + passwordStrength: '', + passwordRetypeState: null + } + }, methods: { + onChangeUsername() { + if (this.username == '') { + this.usernameState = null; + return; + } + + const err = + !this.username.match(/^[a-zA-Z0-9\-]+$/) ? 'invalid-format' : + this.username.length < 3 ? 'min-range' : + this.username.length > 20 ? 'max-range' : + null; + + if (err) { + this.usernameState = err; + return; + } + + this.usernameState = 'wait'; + + this.os.api('username/available', { + username: this.username + }).then(result => { + this.usernameState = result.available ? 'ok' : 'unavailable'; + }).catch(err => { + this.usernameState = 'error'; + }); + }, + onChangePassword() { + if (this.password == '') { + this.passwordStrength = ''; + return; + } + + const strength = getPasswordStrength(this.password); + this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low'; + (this.$refs.passwordMetar as any).style.width = `${strength * 100}%`; + }, + onChangePasswordRetype() { + if (this.retypedPassword == '') { + this.passwordRetypeState = null; + return; + } + + this.passwordRetypeState = this.password == this.retypedPassword ? 'match' : 'not-match'; + }, onSubmit() { + this.os.api('signup', { + username: this.username, + password: this.password, + 'g-recaptcha-response': (window as any).grecaptcha.getResponse() + }).then(() => { + this.os.api('signin', { + username: this.username, + password: this.password + }).then(() => { + location.href = '/'; + }); + }).catch(() => { + alert('%i18n:common.tags.mk-signup.some-error%'); + (window as any).grecaptcha.reset(); + this.recaptchaed = false; + }); } }, + created() { + (window as any).onRecaptchaed = () => { + this.recaptchaed = true; + }; + + (window as any).onRecaptchaExpired = () => { + this.recaptchaed = false; + }; + }, mounted() { const head = document.getElementsByTagName('head')[0]; const script = document.createElement('script'); @@ -63,269 +145,133 @@ export default Vue.extend({ </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 +.form + min-width 302px - [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 + label + display block + margin 16px 0 - &: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 + > .caption + margin 0 0 4px 0 + color #828888 + font-size 0.95em - &:disabled - opacity 0.5 + > [data-fa] + margin-right 0.25em + color #96adac - .agree-tou - padding 4px - border-radius 4px + > .info + display block + margin 4px 0 + font-size 0.8em - &:hover - background #f4f4f4 + > [data-fa] + margin-right 0.3em - &:active - background #eee + &.username + .profile-page-url-preview + display block + margin 4px 8px 0 4px + font-size 0.8em + color #888 - &, * - cursor pointer + &:empty + display none - p - display inline - color #555 + &:not(:empty) + .info + margin-top 0 - button - margin 0 0 32px 0 - padding 16px + &.password + .meter + display block + margin-top 8px 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'); + height 8px + &[data-strength=''] + display none - this.usernameState = null; - this.passwordStrength = ''; - this.passwordRetypeState = null; - this.recaptchaed = false; + &[data-strength='low'] + > .value + background #d73612 - 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); - }); + &[data-strength='medium'] + > .value + background #d7ca12 - this.onChangeUsername = () => { - const username = this.$refs.username.value; + &[data-strength='high'] + > .value + background #61bb22 - 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' - }); - }); - }; + > .value + display block + width 0% + height 100% + background transparent + border-radius 4px + transition all 0.1s ease - this.onChangePassword = () => { - const password = this.$refs.password.value; + [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 - if (password == '') { - this.passwordStrength = ''; - return; - } + &:hover + border-color rgba(0, 0, 0, 0.2) + transition all .1s ease - const strength = getPasswordStrength(password); - this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low'; - this.update(); - this.$refs.passwordMetar.style.width = `${strength * 100}%`; - }; + &: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 - this.onChangePasswordRetype = () => { - const password = this.$refs.password.value; - const retypedPassword = this.$refs.passwordRetype.value; + &:disabled + opacity 0.5 - if (retypedPassword == '') { - this.passwordRetypeState = null; - return; - } + .agree-tou + padding 4px + border-radius 4px - this.passwordRetypeState = password == retypedPassword ? 'match' : 'not-match'; - }; + &:hover + background #f4f4f4 - this.onsubmit = e => { - e.preventDefault(); + &:active + background #eee - const username = this.$refs.username.value; - const password = this.$refs.password.value; + &, * + cursor pointer - const locker = document.body.appendChild(document.createElement('mk-locker')); + p + display inline + color #555 - 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%'); + button + margin 0 0 32px 0 + padding 16px + width 100% + font-size 1em + color #fff + background $theme-color + border-radius 3px - grecaptcha.reset(); - this.recaptchaed = false; + &:hover + background lighten($theme-color, 5%) - locker.parentNode.removeChild(locker); - }); + &:active + background darken($theme-color, 5%) - return false; - }; -</script> +</style> diff --git a/src/web/app/config.ts b/src/web/app/config.ts new file mode 100644 index 0000000000..8357cf6c72 --- /dev/null +++ b/src/web/app/config.ts @@ -0,0 +1,11 @@ +declare const _HOST_: string; +declare const _URL_: string; +declare const _DOCS_URL_: string; +declare const _LANG_: string; +declare const _RECAPTCHA_SITEKEY_: string; + +export const host = _HOST_; +export const url = _URL_; +export const docsUrl = _DOCS_URL_; +export const lang = _LANG_; +export const recaptchaSitekey = _RECAPTCHA_SITEKEY_; diff --git a/src/web/app/desktop/views/pages/welcome.vue b/src/web/app/desktop/views/pages/welcome.vue index 68b5f4cc98..b47e82faed 100644 --- a/src/web/app/desktop/views/pages/welcome.vue +++ b/src/web/app/desktop/views/pages/welcome.vue @@ -18,7 +18,7 @@ </div> </footer> <modal name="signup"> - <mk-signup/> + <mk-signup></mk-signup> </modal> </div> </template> diff --git a/src/web/app/init.ts b/src/web/app/init.ts index 20ea1df8b2..3ae2a8adcd 100644 --- a/src/web/app/init.ts +++ b/src/web/app/init.ts @@ -70,6 +70,9 @@ export default (callback: (os: MiOS, launch: () => Vue) => void, sw = false) => // アプリ基底要素マウント document.body.innerHTML = '<div id="app"></div>'; + // Register global components + require('./common/views/components'); + const launch = () => { return new Vue({ router: new VueRouter({ diff --git a/webpack/module/rules/fa.ts b/webpack/module/rules/fa.ts index 891b78ece2..2679089239 100644 --- a/webpack/module/rules/fa.ts +++ b/webpack/module/rules/fa.ts @@ -7,7 +7,7 @@ import { pattern, replacement } from '../../../src/common/build/fa'; export default () => ({ enforce: 'pre', - test: /\.(tag|js|ts)$/, + test: /\.(vue|js|ts)$/, exclude: /node_modules/, loader: StringReplacePlugin.replace({ replacements: [{ diff --git a/webpack/module/rules/i18n.ts b/webpack/module/rules/i18n.ts index 7261548be5..f8063a311f 100644 --- a/webpack/module/rules/i18n.ts +++ b/webpack/module/rules/i18n.ts @@ -10,7 +10,7 @@ export default lang => { return { enforce: 'pre', - test: /\.(tag|js|ts)$/, + test: /\.(vue|js|ts)$/, exclude: /node_modules/, loader: StringReplacePlugin.replace({ replacements: [{ |