From a1ae832129e8bfe8c082064349e2b9973be5f0e5 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Thu, 14 Jun 2018 14:52:37 +0900 Subject: [PATCH] wip --- .../app/common/views/components/index.ts | 12 +- .../app/common/views/components/signup.vue | 182 +++------------ .../components/{material => ui}/button.vue | 8 +- .../app/common/views/components/ui/form.vue | 28 +++ .../app/common/views/components/ui/group.vue | 23 ++ .../app/common/views/components/ui/input.vue | 215 ++++++++++++++++++ .../app/common/views/components/ui/switch.vue | 199 ++++++++++++++++ .../{material/input.vue => ui/textarea.vue} | 74 +++--- .../app/mobile/views/pages/settings.vue | 170 ++++++-------- .../views/pages/settings/settings.profile.vue | 83 +++---- src/client/app/mobile/views/pages/signup.vue | 2 +- src/client/app/mobile/views/pages/welcome.vue | 8 +- 12 files changed, 658 insertions(+), 346 deletions(-) rename src/client/app/common/views/components/{material => ui}/button.vue (83%) create mode 100644 src/client/app/common/views/components/ui/form.vue create mode 100644 src/client/app/common/views/components/ui/group.vue create mode 100644 src/client/app/common/views/components/ui/input.vue create mode 100644 src/client/app/common/views/components/ui/switch.vue rename src/client/app/common/views/components/{material/input.vue => ui/textarea.vue} (64%) diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index 5dc466857c..060af388b3 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -29,8 +29,12 @@ import fileTypeIcon from './file-type-icon.vue'; import Switch from './switch.vue'; import Othello from './othello.vue'; import welcomeTimeline from './welcome-timeline.vue'; -import uiInput from './material/input.vue'; -import uiButton from './material/button.vue'; +import uiInput from './ui/input.vue'; +import uiButton from './ui/button.vue'; +import uiGroup from './ui/group.vue'; +import uiForm from './ui/form.vue'; +import uiTextarea from './ui/textarea.vue'; +import uiSwitch from './ui/switch.vue'; Vue.component('mk-analog-clock', analogClock); Vue.component('mk-menu', menu); @@ -63,3 +67,7 @@ Vue.component('mk-othello', Othello); Vue.component('mk-welcome-timeline', welcomeTimeline); Vue.component('ui-input', uiInput); Vue.component('ui-button', uiButton); +Vue.component('ui-group', uiGroup); +Vue.component('ui-form', uiForm); +Vue.component('ui-textarea', uiTextarea); +Vue.component('ui-switch', uiSwitch); diff --git a/src/client/app/common/views/components/signup.vue b/src/client/app/common/views/components/signup.vue index 3adb10f2c3..d1621a4848 100644 --- a/src/client/app/common/views/components/signup.vue +++ b/src/client/app/common/views/components/signup.vue @@ -1,50 +1,40 @@ <template> <form class="mk-signup" @submit.prevent="onSubmit" autocomplete="off"> - <label class="username"> - <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" autocomplete="off" required @input="onChangeUsername"> - <span>%i18n:@username%</span> - <span slot="prefix">@</span> - <span slot="suffix">@{{ host }}</span> - <p slot="text" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw%%i18n:@checking%</p> - <p slot="text" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw%%i18n:@available%</p> - <p slot="text" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@unavailable%</p> - <p slot="text" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@error%</p> - <p slot="text" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@invalid-format%</p> - <p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@too-short%</p> - <p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@too-long%</p> - </ui-input> - </label> - <label class="password"> - <ui-input v-model="password" type="password" autocomplete="off" required @input="onChangePassword"> - <span>%i18n:@password%</span> - <span slot="prefix">%fa:lock%</span> - <div slot="text"> - - </div> - </ui-input> - <div class="meter" v-show="passwordStrength != ''" :data-strength="passwordStrength"> - <div class="value" ref="passwordMetar"></div> + <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" autocomplete="off" required @input="onChangeUsername"> + <span>%i18n:@username%</span> + <span slot="prefix">@</span> + <span slot="suffix">@{{ host }}</span> + <p slot="text" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw% %i18n:@checking%</p> + <p slot="text" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw% %i18n:@available%</p> + <p slot="text" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@unavailable%</p> + <p slot="text" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@error%</p> + <p slot="text" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@invalid-format%</p> + <p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p> + <p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p> + </ui-input> + <ui-input v-model="password" type="password" autocomplete="off" required @input="onChangePassword" :with-password-meter="true"> + <span>%i18n:@password%</span> + <span slot="prefix">%fa:lock%</span> + <div slot="text"> + <p slot="text" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@weak-password%</p> + <p slot="text" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw% %i18n:@normal-password%</p> + <p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p> </div> - <p class="info" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@weak-password%</p> - <p class="info" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw%%i18n:@normal-password%</p> - <p class="info" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw%%i18n:@strong-password%</p> - </label> - <label class="retype-password"> - <ui-input v-model="retypedPassword" type="password" autocomplete="off" required @input="onChangePasswordRetype"> - <span>%i18n:@password% (%i18n:@retype%)</span> - <span slot="prefix">%fa:lock%</span> - </ui-input> - <p class="info" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw%%i18n:@password-matched%</p> - <p class="info" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@password-not-matched%</p> - </label> - <label class="recaptcha"> - <div class="g-recaptcha" :data-sitekey="recaptchaSitekey"></div> - </label> - <label class="agree-tou"> + </ui-input> + <ui-input v-model="retypedPassword" type="password" autocomplete="off" required @input="onChangePasswordRetype"> + <span>%i18n:@password% (%i18n:@retype%)</span> + <span slot="prefix">%fa:lock%</span> + <div slot="text"> + <p slot="text" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw% %i18n:@password-matched%</p> + <p slot="text" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@password-not-matched%</p> + </div> + </ui-input> + <div class="g-recaptcha" :data-sitekey="recaptchaSitekey" style="margin: 16px 0;"></div> + <label class="agree-tou" style="display: block; margin: 16px 0;"> <input name="agree-tou" type="checkbox" autocomplete="off" required/> <p><a :href="touUrl" target="_blank">利用規約</a>に同意する</p> </label> - <button type="submit">%i18n:@create%</button> + <ui-button type="submit">%i18n:@create%</ui-button> </form> </template> @@ -112,7 +102,6 @@ export default Vue.extend({ 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 == '') { @@ -156,100 +145,6 @@ export default Vue.extend({ .mk-signup min-width 302px - label - display block - margin 0 0 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(#000, 0.1) - border-radius 4px - box-shadow 0 0 0 114514px #fff inset - transition all .3s ease - - &:hover - border-color rgba(#000, 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 @@ -267,19 +162,4 @@ export default Vue.extend({ display inline color #555 - button - margin 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> diff --git a/src/client/app/common/views/components/material/button.vue b/src/client/app/common/views/components/ui/button.vue similarity index 83% rename from src/client/app/common/views/components/material/button.vue rename to src/client/app/common/views/components/ui/button.vue index 8dacedbac6..57747fd469 100644 --- a/src/client/app/common/views/components/material/button.vue +++ b/src/client/app/common/views/components/ui/button.vue @@ -25,7 +25,7 @@ export default Vue.extend({ > button display block width 100% - margin 32px 0 16px 0 + margin 0 padding 0 color $theme-color-foreground font-weight bold @@ -37,4 +37,10 @@ export default Vue.extend({ outline none box-shadow none + &:hover + background lighten($theme-color, 5%) + + &:active + background darken($theme-color, 5%) + </style> diff --git a/src/client/app/common/views/components/ui/form.vue b/src/client/app/common/views/components/ui/form.vue new file mode 100644 index 0000000000..0893af1bce --- /dev/null +++ b/src/client/app/common/views/components/ui/form.vue @@ -0,0 +1,28 @@ +<template> +<div class="ui-form"> + <fieldset :disabled="disabled"> + <slot></slot> + </fieldset> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +export default Vue.extend({ + props: { + disabled: { + type: String, + required: false + } + } +}); +</script> + +<style lang="stylus" scoped> +@import '~const.styl' + +.ui-form + > fieldset + border none + +</style> diff --git a/src/client/app/common/views/components/ui/group.vue b/src/client/app/common/views/components/ui/group.vue new file mode 100644 index 0000000000..fb29458ce8 --- /dev/null +++ b/src/client/app/common/views/components/ui/group.vue @@ -0,0 +1,23 @@ +<template> +<div class="ui-group"> + <header> + <slot name="title"></slot> + </header> + + <slot></slot> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +export default Vue.extend({}); +</script> + +<style lang="stylus" scoped> +@import '~const.styl' + +.ui-group + > header + font-weight bold + +</style> diff --git a/src/client/app/common/views/components/ui/input.vue b/src/client/app/common/views/components/ui/input.vue new file mode 100644 index 0000000000..7461aac7fe --- /dev/null +++ b/src/client/app/common/views/components/ui/input.vue @@ -0,0 +1,215 @@ +<template> +<div class="ui-input" :class="{ focused, filled }"> + <div class="input" @click="focus"> + <div class="password-meter" v-if="withPasswordMeter" v-show="passwordStrength != ''" :data-strength="passwordStrength"> + <div class="value" ref="passwordMetar"></div> + </div> + <span class="label" ref="label"><slot></slot></span> + <div class="prefix" ref="prefix"><slot name="prefix"></slot></div> + <input ref="input" + :type="type" + :value="value" + :required="required" + :readonly="readonly" + :pattern="pattern" + :autocomplete="autocomplete" + @input="$emit('input', $event.target.value)" + @focus="focused = true" + @blur="focused = false"> + <div class="suffix"><slot name="suffix"></slot></div> + </div> + <div class="text"><slot name="text"></slot></div> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +const getPasswordStrength = require('syuilo-password-strength'); + +export default Vue.extend({ + props: { + value: { + required: false + }, + type: { + type: String, + required: false + }, + required: { + type: Boolean, + required: false + }, + readonly: { + type: Boolean, + required: false + }, + pattern: { + type: String, + required: false + }, + autocomplete: { + type: String, + required: false + }, + withPasswordMeter: { + type: Boolean, + required: false, + default: false + } + }, + data() { + return { + focused: false, + passwordStrength: '' + } + }, + computed: { + filled(): boolean { + return this.value != '' && this.value != null; + } + }, + watch: { + value(v) { + if (this.withPasswordMeter) { + if (v == '') { + this.passwordStrength = ''; + return; + } + + const strength = getPasswordStrength(v); + this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low'; + (this.$refs.passwordMetar as any).style.width = `${strength * 100}%`; + } + } + }, + mounted() { + if (this.$refs.prefix) { + this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px'; + } + }, + methods: { + focus() { + this.$refs.input.focus(); + } + } +}); +</script> + +<style lang="stylus" scoped> +@import '~const.styl' + +.ui-input + margin 32px 0 + + > .input + display flex + padding 6px 12px + background rgba(#000, 0.035) + border-radius 6px + + > .password-meter + position absolute + top 0 + left 0 + width 100% + height 100% + border-radius 6px + overflow hidden + opacity 0.3 + + &[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 6px + transition all 0.1s ease + + > .label + position absolute + top 6px + left 0 + pointer-events none + transition 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) + transition-duration 0.3s + font-size 16px + line-height 32px + color rgba(#000, 0.54) + pointer-events none + //will-change transform + transform-origin top left + transform scale(1) + + > input + display block + flex 1 + width 100% + padding 0 + font inherit + font-weight bold + font-size 16px + line-height 32px + background transparent + border none + border-radius 0 + outline none + box-shadow none + + > .prefix + > .suffix + display block + align-self center + justify-self center + font-size 16px + line-height 32px + color rgba(#000, 0.54) + pointer-events none + + > * + display block + min-width 16px + + > .prefix + padding-right 4px + + > .suffix + padding-left 4px + + > .text + margin 6px 0 + font-size 13px + + * + margin 0 + + &.focused + > .input + background rgba(#000, 0.05) + + > .label + color $theme-color + + &.focused + &.filled + > .input + > .label + top -24px + left 0 !important + transform scale(0.8) + +</style> diff --git a/src/client/app/common/views/components/ui/switch.vue b/src/client/app/common/views/components/ui/switch.vue new file mode 100644 index 0000000000..2cac6262f1 --- /dev/null +++ b/src/client/app/common/views/components/ui/switch.vue @@ -0,0 +1,199 @@ +<template> +<div + class="ui-switch" + :class="{ disabled, checked }" + role="switch" + :aria-checked="checked" + :aria-disabled="disabled" + @click="switchValue" + @mouseover="mouseenter" +> + <input + type="checkbox" + @change="handleChange" + ref="input" + :disabled="disabled" + @keydown.enter="switchValue" + > + <span class="button"> + <span :style="{ transform }"></span> + </span> + <span class="label"> + <span :aria-hidden="!checked"><slot></slot></span> + <p :aria-hidden="!checked"> + <slot name="text"></slot> + </p> + </span> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +export default Vue.extend({ + props: { + value: { + type: Boolean, + default: false + }, + disabled: { + type: Boolean, + default: false + } + },/* + created() { + if (!~[true, false].indexOf(this.value)) { + this.$emit('input', false); + } + },*/ + computed: { + checked(): boolean { + return this.value; + }, + transform(): string { + return this.checked ? 'translate3d(14px, 0, 0)' : ''; + } + }, + watch: { + value() { + (this.$el).style.transition = 'all 0.3s'; + (this.$refs.input as any).checked = this.checked; + } + }, + mounted() { + (this.$refs.input as any).checked = this.checked; + }, + methods: { + mouseenter() { + (this.$el).style.transition = 'all 0s'; + }, + handleChange() { + (this.$el).style.transition = 'all 0.3s'; + this.$emit('input', !this.checked); + this.$emit('change', !this.checked); + this.$nextTick(() => { + // set input's checked property + // in case parent refuses to change component's value + (this.$refs.input as any).checked = this.checked; + }); + }, + switchValue() { + !this.disabled && this.handleChange(); + } + } +}); +</script> + +<style lang="stylus" scoped> +@import '~const.styl' + +root(isDark) + display flex + margin 16px 0 + cursor pointer + transition all 0.3s + + > * + user-select none + + &.disabled + opacity 0.6 + cursor not-allowed + + &.checked + > .button + background-color $theme-color + border-color $theme-color + + > .label + > span + color $theme-color + + &:hover + > .label + > span + color darken($theme-color, 10%) + + > .button + background darken($theme-color, 10%) + border-color darken($theme-color, 10%) + + &:hover + > .label + > span + color isDark ? #fff : #2e3338 + + > .button + $color = isDark ? #15181d : #ced2da + background $color + border-color $color + + > input + position absolute + width 0 + height 0 + opacity 0 + margin 0 + + &:focus + .button + &: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 14px + + > .button + $color = isDark ? #1c1f25 : #dcdfe6 + + display inline-block + margin 0 + width 46px + min-width 46px + height 32px + min-height 32px + background $color + border 1px solid $color + outline none + border-radius 6px + transition inherit + + > * + position absolute + top 1px + left 1px + border-radius 6px + transition transform 0.3s + width 28px + height 28px + background-color #fff + + > .label + margin-left 8px + display block + font-size 16px + cursor pointer + transition inherit + + > span + display block + line-height 32px + font-weight bold + color isDark ? #c4ccd2 : #4a535a + transition inherit + + > p + margin 0 + //font-size 90% + color isDark ? #78858e : #9daab3 + +.ui-switch[data-darkmode] + root(true) + +.ui-switch:not([data-darkmode]) + root(false) + +</style> diff --git a/src/client/app/common/views/components/material/input.vue b/src/client/app/common/views/components/ui/textarea.vue similarity index 64% rename from src/client/app/common/views/components/material/input.vue rename to src/client/app/common/views/components/ui/textarea.vue index 6564b3aa6c..0a9f60f1bc 100644 --- a/src/client/app/common/views/components/material/input.vue +++ b/src/client/app/common/views/components/ui/textarea.vue @@ -1,17 +1,17 @@ <template> -<div class="ui-input" :class="{ focused, filled }"> +<div class="ui-textarea" :class="{ focused, filled }"> <div class="input"> <span class="label" ref="label"><slot></slot></span> - <div class="prefix" ref="prefix" @click="focus"><slot name="prefix"></slot></div> - <input ref="input" - :type="type" + <textarea ref="input" :value="value" :required="required" :readonly="readonly" + :pattern="pattern" + :autocomplete="autocomplete" @input="$emit('input', $event.target.value)" @focus="focused = true" @blur="focused = false"> - <div class="suffix" @click="focus"><slot name="suffix"></slot></div> + </textarea> </div> <div class="text"><slot name="text"></slot></div> </div> @@ -19,15 +19,13 @@ <script lang="ts"> import Vue from 'vue'; +const getPasswordStrength = require('syuilo-password-strength'); + export default Vue.extend({ props: { value: { required: false }, - type: { - type: String, - required: false - }, required: { type: Boolean, required: false @@ -35,11 +33,20 @@ export default Vue.extend({ readonly: { type: Boolean, required: false + }, + pattern: { + type: String, + required: false + }, + autocomplete: { + type: String, + required: false } }, data() { return { - focused: false + focused: false, + passwordStrength: '' } }, computed: { @@ -47,9 +54,6 @@ export default Vue.extend({ return this.value != '' && this.value != null; } }, - mounted() { - this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px'; - }, methods: { focus() { this.$refs.input.focus(); @@ -61,20 +65,18 @@ export default Vue.extend({ <style lang="stylus" scoped> @import '~const.styl' -.ui-input - margin-bottom 16px - padding-top 16px +.ui-textarea + margin 32px 0 > .input - display flex - padding 6px 12px + padding 12px background rgba(#000, 0.035) border-radius 6px > .label position absolute top 6px - left 0 + left 12px pointer-events none transition 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) transition-duration 0.3s @@ -82,42 +84,29 @@ export default Vue.extend({ line-height 32px color rgba(#000, 0.54) pointer-events none + //will-change transform + transform-origin top left + transform scale(1) - > input + > textarea display block - flex 1 width 100% + min-height 100px padding 0 font inherit font-weight bold font-size 16px - line-height 32px background transparent border none border-radius 0 outline none box-shadow none - > .prefix - > .suffix - display block - align-self center - justify-self center - font-size 16px - line-height 32px - color rgba(#000, 0.54) - - > .prefix - padding-right 4px - - > .suffix - padding-left 4px - > .text - margin 8px 0 - font-size 14px + margin 6px 0 + font-size 13px - > p + * margin 0 &.focused @@ -131,9 +120,8 @@ export default Vue.extend({ &.filled > .input > .label - top -20px + top -24px left 0 !important - font-size 12px - line-height 20px + transform scale(0.8) </style> diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue index 8da7a76633..716f7afc0c 100644 --- a/src/client/app/mobile/views/pages/settings.vue +++ b/src/client/app/mobile/views/pages/settings.vue @@ -6,125 +6,105 @@ <div> <x-profile/> - <md-card> - <md-card-header> - <div class="md-title">%fa:palette% %i18n:@design%</div> - </md-card-header> + <ui-group> + <div slot="title">%fa:palette% %i18n:@design%</div> + + <div> + <ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch> + </div> + + <div> + <ui-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</ui-switch> + </div> + + <div> + <div class="md-body-2">%i18n:@timeline%</div> - <md-card-content> <div> - <md-switch v-model="darkmode">%i18n:@dark-mode%</md-switch> + <ui-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget">%i18n:@show-reply-target%</ui-switch> </div> <div> - <md-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</md-switch> + <ui-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes">%i18n:@show-my-renotes%</ui-switch> </div> <div> - <div class="md-body-2">%i18n:@timeline%</div> - - <div> - <md-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget">%i18n:@show-reply-target%</md-switch> - </div> - - <div> - <md-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes">%i18n:@show-my-renotes%</md-switch> - </div> - - <div> - <md-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes">%i18n:@show-renoted-my-notes%</md-switch> - </div> + <ui-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes">%i18n:@show-renoted-my-notes%</ui-switch> </div> + </div> - <div> - <div class="md-body-2">%i18n:@post-style%</div> + <div> + <div class="md-body-2">%i18n:@post-style%</div> - <md-radio v-model="postStyle" value="standard">%i18n:@post-style-standard%</md-radio> - <md-radio v-model="postStyle" value="smart">%i18n:@post-style-smart%</md-radio> - </div> - </md-card-content> - </md-card> + <md-radio v-model="postStyle" value="standard">%i18n:@post-style-standard%</md-radio> + <md-radio v-model="postStyle" value="smart">%i18n:@post-style-smart%</md-radio> + </div> + </ui-group> - <md-card> - <md-card-header> - <div class="md-title">%fa:cog% %i18n:@behavior%</div> - </md-card-header> + <ui-group> + <div slot="title">%fa:cog% %i18n:@behavior%</div> - <md-card-content> - <div> - <md-switch v-model="$store.state.settings.fetchOnScroll" @change="onChangeFetchOnScroll">%i18n:@fetch-on-scroll%</md-switch> - </div> + <div> + <ui-switch v-model="$store.state.settings.fetchOnScroll" @change="onChangeFetchOnScroll">%i18n:@fetch-on-scroll%</ui-switch> + </div> - <div> - <md-switch v-model="$store.state.settings.disableViaMobile" @change="onChangeDisableViaMobile">%i18n:@disable-via-mobile%</md-switch> - </div> + <div> + <ui-switch v-model="$store.state.settings.disableViaMobile" @change="onChangeDisableViaMobile">%i18n:@disable-via-mobile%</ui-switch> + </div> - <div> - <md-switch v-model="loadRawImages">%i18n:@load-raw-images%</md-switch> - </div> + <div> + <ui-switch v-model="loadRawImages">%i18n:@load-raw-images%</ui-switch> + </div> - <div> - <md-switch v-model="$store.state.settings.loadRemoteMedia" @change="onChangeLoadRemoteMedia">%i18n:@load-remote-media%</md-switch> - </div> + <div> + <ui-switch v-model="$store.state.settings.loadRemoteMedia" @change="onChangeLoadRemoteMedia">%i18n:@load-remote-media%</ui-switch> + </div> - <div> - <md-switch v-model="lightmode">%i18n:@i-am-under-limited-internet%</md-switch> - </div> - </md-card-content> - </md-card> + <div> + <ui-switch v-model="lightmode">%i18n:@i-am-under-limited-internet%</ui-switch> + </div> + </ui-group> - <md-card> - <md-card-header> - <div class="md-title">%fa:language% %i18n:@lang%</div> - </md-card-header> + <ui-group> + <div slot="title">%fa:language% %i18n:@lang%</div> - <md-card-content> - <md-field> - <md-select v-model="lang" placeholder="%i18n:@auto%"> - <md-optgroup label="%i18n:@recommended%"> - <md-option value="">%i18n:@auto%</md-option> - </md-optgroup> + <md-field> + <md-select v-model="lang" placeholder="%i18n:@auto%"> + <md-optgroup label="%i18n:@recommended%"> + <md-option value="">%i18n:@auto%</md-option> + </md-optgroup> - <md-optgroup label="%i18n:@specify-language%"> - <md-option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</md-option> - </md-optgroup> - </md-select> - </md-field> - <span class="md-helper-text">%fa:info-circle% %i18n:@lang-tip%</span> - </md-card-content> - </md-card> + <md-optgroup label="%i18n:@specify-language%"> + <md-option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</md-option> + </md-optgroup> + </md-select> + </md-field> + <span class="md-helper-text">%fa:info-circle% %i18n:@lang-tip%</span> + </ui-group> - <md-card> - <md-card-header> - <div class="md-title">%fa:B twitter% %i18n:@twitter%</div> - </md-card-header> + <ui-group> + <div slot="title">%fa:B twitter% %i18n:@twitter%</div> - <md-card-content> - <p class="account" v-if="$store.state.i.twitter"><a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p> - <p> - <a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ $store.state.i.twitter ? '%i18n:@twitter-reconnect%' : '%i18n:@twitter-connect%' }}</a> - <span v-if="$store.state.i.twitter"> or </span> - <a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter">%i18n:@twitter-disconnect%</a> - </p> - </md-card-content> - </md-card> + <p class="account" v-if="$store.state.i.twitter"><a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p> + <p> + <a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ $store.state.i.twitter ? '%i18n:@twitter-reconnect%' : '%i18n:@twitter-connect%' }}</a> + <span v-if="$store.state.i.twitter"> or </span> + <a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter">%i18n:@twitter-disconnect%</a> + </p> + </ui-group> - <md-card> - <md-card-header> - <div class="md-title">%fa:sync-alt% %i18n:@update%</div> - </md-card-header> + <ui-group> + <div slot="title">%fa:sync-alt% %i18n:@update%</div> - <md-card-content> - <div>%i18n:@version% <i>{{ version }}</i></div> - <template v-if="latestVersion !== undefined"> - <div>%i18n:@latest-version% <i>{{ latestVersion ? latestVersion : version }}</i></div> - </template> - <md-button class="md-raised md-primary" @click="checkForUpdate" :disabled="checkingForUpdate"> - <template v-if="checkingForUpdate">%i18n:@update-checking%<mk-ellipsis/></template> - <template v-else>%i18n:@check-for-updates%</template> - </md-button> - </md-card-content> - </md-card> + <div>%i18n:@version% <i>{{ version }}</i></div> + <template v-if="latestVersion !== undefined"> + <div>%i18n:@latest-version% <i>{{ latestVersion ? latestVersion : version }}</i></div> + </template> + <md-button class="md-raised md-primary" @click="checkForUpdate" :disabled="checkingForUpdate"> + <template v-if="checkingForUpdate">%i18n:@update-checking%<mk-ellipsis/></template> + <template v-else>%i18n:@check-for-updates%</template> + </md-button> + </ui-group> </div> <p><small>ver {{ version }} ({{ codename }})</small></p> </main> diff --git a/src/client/app/mobile/views/pages/settings/settings.profile.vue b/src/client/app/mobile/views/pages/settings/settings.profile.vue index f3444eb1f0..73d876d14e 100644 --- a/src/client/app/mobile/views/pages/settings/settings.profile.vue +++ b/src/client/app/mobile/views/pages/settings/settings.profile.vue @@ -1,62 +1,47 @@ <template> - <md-card> - <md-card-header> - <div class="md-title">%fa:pencil-alt% %i18n:@title%</div> - </md-card-header> +<ui-group> + <div slot="title">%fa:pencil-alt% %i18n:@title%</div> - <md-card-content> - <md-field> - <label>%i18n:@name%</label> - <md-input v-model="name" :disabled="saving" md-counter="30"/> - </md-field> + <ui-form :disabled="saving"> + <ui-input v-model="name" :max="30"> + <span>%i18n:@name%</span> + </ui-input> - <md-field> - <label>%i18n:@account%</label> - <span class="md-prefix">@</span> - <md-input v-model="username" readonly></md-input> - <span class="md-suffix">@{{ host }}</span> - </md-field> + <ui-input v-model="username" readonly> + <span>%i18n:@account%</span> + <span slot="prefix">@</span> + <span slot="suffix">@{{ host }}</span> + </ui-input> - <md-field> - <md-icon>%fa:map-marker-alt%</md-icon> - <label>%i18n:@location%</label> - <md-input v-model="location" :disabled="saving"/> - </md-field> + <ui-input v-model="location"> + <span>%i18n:@location%</span> + <span slot="prefix">%fa:map-marker-alt%</span> + </ui-input> - <md-field> - <md-icon>%fa:birthday-cake%</md-icon> - <label>%i18n:@birthday%</label> - <md-input type="date" v-model="birthday" :disabled="saving"/> - </md-field> + <ui-input v-model="birthday" type="date"> + <span>%i18n:@birthday%</span> + <span slot="prefix">%fa:birthday-cake%</span> + </ui-input> - <md-field> - <label>%i18n:@description%</label> - <md-textarea v-model="description" :disabled="saving" md-counter="500"/> - </md-field> + <ui-textarea v-model="description" :max="500"> + <span>%i18n:@description%</span> + </ui-textarea> - <md-field> - <label>%i18n:@avatar%</label> - <md-file @md-change="onAvatarChange"/> - </md-field> + <ui-input type="file" @change="onAvatarChange"> + <span>%i18n:@avatar%</span> + <span slot="prefix">%fa:picture-o%</span> + </ui-input> - <md-field> - <label>%i18n:@banner%</label> - <md-file @md-change="onBannerChange"/> - </md-field> + <ui-input type="file" @change="onBannerChange"> + <span>%i18n:@banner%</span> + <span slot="prefix">%fa:picture-o%</span> + </ui-input> - <md-dialog-alert - :md-active.sync="uploading" - md-content="%18n:!@uploading%"/> + <ui-switch v-model="isCat">%i18n:@is-cat%</ui-switch> - <div> - <md-switch v-model="isCat">%i18n:@is-cat%</md-switch> - </div> - </md-card-content> - - <md-card-actions> - <md-button class="md-primary" :disabled="saving" @click="save">%i18n:@save%</md-button> - </md-card-actions> - </md-card> + <ui-button @click="save">%i18n:@save%</ui-button> + </ui-form> +</ui-group> </template> <script lang="ts"> diff --git a/src/client/app/mobile/views/pages/signup.vue b/src/client/app/mobile/views/pages/signup.vue index f2b29bca60..47384e2b3c 100644 --- a/src/client/app/mobile/views/pages/signup.vue +++ b/src/client/app/mobile/views/pages/signup.vue @@ -18,7 +18,7 @@ export default Vue.extend({}); h1 margin 0 - padding 8px + padding 8px 0 0 0 font-size 1.5em font-weight bold color #444 diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue index 01b20aa472..3b37a185bd 100644 --- a/src/client/app/mobile/views/pages/welcome.vue +++ b/src/client/app/mobile/views/pages/welcome.vue @@ -10,16 +10,16 @@ </div> <div class="login"> <form @submit.prevent="onSubmit"> - <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" placeholder="ユーザー名" autofocus required @change="onUsernameChange"> + <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" autofocus required @change="onUsernameChange"> <span>ユーザー名</span> <span slot="prefix">@</span> <span slot="suffix">@{{ host }}</span> </ui-input> - <ui-input v-model="password" type="password" placeholder="パスワード" required> + <ui-input v-model="password" type="password" required> <span>パスワード</span> <span slot="prefix">%fa:lock%</span> </ui-input> - <ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" placeholder="トークン" required/> + <ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required/> <ui-button type="submit" :disabled="signing">{{ signing ? 'ログインしています' : 'ログイン' }}</ui-button> </form> <div> @@ -113,7 +113,7 @@ export default Vue.extend({ > .about margin-top 16px padding 16px - color #444 + color #555 background #fff border-radius 6px