From e6e02ece89e9e2af2ae0aa4c57cb9fcdb3d5b890 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Thu, 14 Jun 2018 06:29:01 +0900 Subject: [PATCH 01/11] wip --- package.json | 1 - src/client/app/app.styl | 5 - .../app/common/views/components/index.ts | 2 + .../views/components/material/input.vue | 129 ++++++++++++++++++ src/client/app/mobile/script.ts | 15 -- src/client/app/mobile/style.styl | 3 - src/client/app/mobile/views/pages/welcome.vue | 18 ++- .../app/mobile/views/widgets/profile.vue | 2 +- src/client/md.scss | 13 -- 9 files changed, 145 insertions(+), 43 deletions(-) create mode 100644 src/client/app/common/views/components/material/input.vue delete mode 100644 src/client/md.scss diff --git a/package.json b/package.json index 4b207d5e5a..b1b8888b5c 100644 --- a/package.json +++ b/package.json @@ -211,7 +211,6 @@ "vue-js-modal": "1.3.13", "vue-json-tree-view": "2.1.4", "vue-loader": "15.2.1", - "vue-material": "^1.0.0-beta-10.2", "vue-router": "3.0.1", "vue-template-compiler": "2.5.16", "vuedraggable": "2.16.0", diff --git a/src/client/app/app.styl b/src/client/app/app.styl index ba694b73ae..431b9daa65 100644 --- a/src/client/app/app.styl +++ b/src/client/app/app.styl @@ -7,11 +7,6 @@ html cursor progress !important body - // for md - font-size 16px !important - line-height initial !important - letter-spacing initial !important - overflow-wrap break-word #error diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index 803854468e..659c2aca2a 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -29,6 +29,7 @@ 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'; Vue.component('mk-analog-clock', analogClock); Vue.component('mk-menu', menu); @@ -59,3 +60,4 @@ Vue.component('mk-file-type-icon', fileTypeIcon); Vue.component('mk-switch', Switch); Vue.component('mk-othello', Othello); Vue.component('mk-welcome-timeline', welcomeTimeline); +Vue.component('ui-input', uiInput); diff --git a/src/client/app/common/views/components/material/input.vue b/src/client/app/common/views/components/material/input.vue new file mode 100644 index 0000000000..42ff0bb4b8 --- /dev/null +++ b/src/client/app/common/views/components/material/input.vue @@ -0,0 +1,129 @@ +<template> +<div class="ui-input" :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" :value="value" @input="$emit('input', $event.target.value)" @focus="focused = true" @blur="focused = false"> + <div class="suffix" @click="focus"><slot name="suffix"></slot></div> + </div> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +export default Vue.extend({ + props: ['value'], + data() { + return { + focused: false + } + }, + computed: { + filled(): boolean { + return this.value != '' && this.value != null; + } + }, + mounted() { + this.$refs.label.style.left = this.$refs.prefix.offsetWidth + 'px'; + }, + methods: { + focus() { + this.$refs.input.focus(); + } + } +}); +</script> + +<style lang="stylus" scoped> +@import '~const.styl' + +.ui-input + padding-bottom 16px + + > .input + display flex + margin-top 16px + + &:before + content '' + display block + position absolute + bottom 0 + left 0 + right 0 + height 1px + background rgba(#000, 0.42) + + &:after + content '' + display block + position absolute + bottom 0 + left 0 + right 0 + height 2px + background $theme-color + opacity 0 + transform scaleX(0.12) + transition border 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) + will-change border opacity transform + + > .label + position absolute + top 0 + 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 + + > input + display block + flex 1 + width 100% + padding 0 + 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 + + &.focused + > .input + &:after + opacity 1 + transform scaleX(1) + + > .label + color $theme-color + + &.focused + &.filled + > .input + > .label + top -16px + left 0 !important + font-size 12px + line-height 20px + +</style> diff --git a/src/client/app/mobile/script.ts b/src/client/app/mobile/script.ts index d505b38dcc..a6f4359432 100644 --- a/src/client/app/mobile/script.ts +++ b/src/client/app/mobile/script.ts @@ -5,10 +5,6 @@ import Vue from 'vue'; import VueRouter from 'vue-router'; -import { MdCard, MdButton, MdField, MdMenu, MdList, MdSwitch, MdSubheader, MdDialog, MdDialogAlert, MdRadio } from 'vue-material/dist/components'; -import 'vue-material/dist/vue-material.min.css'; -import 'vue-material/dist/theme/default.css'; - // Style import './style.styl'; import '../../element.scss'; @@ -44,17 +40,6 @@ import MkSettings from './views/pages/settings.vue'; import MkOthello from './views/pages/othello.vue'; import MkTag from './views/pages/tag.vue'; -Vue.use(MdCard); -Vue.use(MdButton); -Vue.use(MdField); -Vue.use(MdMenu); -Vue.use(MdList); -Vue.use(MdSwitch); -Vue.use(MdSubheader); -Vue.use(MdDialog); -Vue.use(MdDialogAlert); -Vue.use(MdRadio); - /** * init */ diff --git a/src/client/app/mobile/style.styl b/src/client/app/mobile/style.styl index d1ab044eaf..df8f4a8fae 100644 --- a/src/client/app/mobile/style.styl +++ b/src/client/app/mobile/style.styl @@ -10,9 +10,6 @@ html height 100% background #ececed !important - // for md - transition none !important - &[data-darkmode] background #191B22 !important diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue index 64cfa5a46c..ceb1abb9a0 100644 --- a/src/client/app/mobile/views/pages/welcome.vue +++ b/src/client/app/mobile/views/pages/welcome.vue @@ -7,9 +7,16 @@ <p>%fa:lock% ログイン</p> <div> <form @submit.prevent="onSubmit"> - <input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" placeholder="ユーザー名" autofocus required @change="onUsernameChange"/> - <input v-model="password" type="password" placeholder="パスワード" required/> - <input v-if="user && user.twoFactorEnabled" v-model="token" type="number" placeholder="トークン" required/> + <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" placeholder="ユーザー名" 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> + <span>パスワード</span> + <span slot="prefix">%fa:lock%</span> + </ui-input> + <ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" placeholder="トークン" required/> <button type="submit" :disabled="signing">{{ signing ? 'ログインしています' : 'ログイン' }}</button> </form> <div> @@ -33,7 +40,7 @@ <script lang="ts"> import Vue from 'vue'; -import { apiUrl, copyright } from '../../../config'; +import { apiUrl, copyright, host } from '../../../config'; export default Vue.extend({ data() { @@ -45,7 +52,8 @@ export default Vue.extend({ token: '', apiUrl, copyright, - users: [] + users: [], + host }; }, mounted() { diff --git a/src/client/app/mobile/views/widgets/profile.vue b/src/client/app/mobile/views/widgets/profile.vue index beae1ffa36..a94f7e94b8 100644 --- a/src/client/app/mobile/views/widgets/profile.vue +++ b/src/client/app/mobile/views/widgets/profile.vue @@ -56,7 +56,7 @@ export default define({ left 92px margin 0 line-height 100px - color #fff !important // !important is for md + color #fff font-weight bold text-shadow 0 0 8px rgba(#000, 0.5) diff --git a/src/client/md.scss b/src/client/md.scss deleted file mode 100644 index 8368365885..0000000000 --- a/src/client/md.scss +++ /dev/null @@ -1,13 +0,0 @@ -/* SEE: https://vuematerial.io/themes/configuration */ - -@import '../const.json'; - -@import "~vue-material/dist/theme/engine"; - -@include md-register-theme("default", ( - primary: $themeColor, - accent: $themeColor -)); - -@import "~vue-material/dist/components/MdButton/theme"; -@import "~vue-material/dist/components/MdField/theme"; From 8814fc9c9c0614215f7e5dbe3ec1316c49e2b68d Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Thu, 14 Jun 2018 07:22:50 +0900 Subject: [PATCH 02/11] wip --- .../app/common/views/components/index.ts | 2 + .../views/components/material/button.vue | 39 ++++++ .../views/components/material/input.vue | 41 ++---- src/client/app/mobile/script.ts | 2 - src/client/app/mobile/views/pages/welcome.vue | 123 ++++++------------ 5 files changed, 92 insertions(+), 115 deletions(-) create mode 100644 src/client/app/common/views/components/material/button.vue diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index 659c2aca2a..5dc466857c 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -30,6 +30,7 @@ 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'; Vue.component('mk-analog-clock', analogClock); Vue.component('mk-menu', menu); @@ -61,3 +62,4 @@ Vue.component('mk-switch', Switch); Vue.component('mk-othello', Othello); Vue.component('mk-welcome-timeline', welcomeTimeline); Vue.component('ui-input', uiInput); +Vue.component('ui-button', uiButton); diff --git a/src/client/app/common/views/components/material/button.vue b/src/client/app/common/views/components/material/button.vue new file mode 100644 index 0000000000..0c768cf4cc --- /dev/null +++ b/src/client/app/common/views/components/material/button.vue @@ -0,0 +1,39 @@ +<template> +<div class="ui-button"> + <button> + <slot></slot> + </button> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +export default Vue.extend({ + props: { + type: { + type: String, + required: false + } + } +}); +</script> + +<style lang="stylus" scoped> +@import '~const.styl' + +.ui-button + > button + display block + width 100% + padding 0 + color $theme-color-foreground + font-weight bold + font-size 16px + line-height 44px + background $theme-color + border none + border-radius 6px + outline none + box-shadow none + +</style> diff --git a/src/client/app/common/views/components/material/input.vue b/src/client/app/common/views/components/material/input.vue index 42ff0bb4b8..fe64354908 100644 --- a/src/client/app/common/views/components/material/input.vue +++ b/src/client/app/common/views/components/material/input.vue @@ -24,7 +24,7 @@ export default Vue.extend({ } }, mounted() { - this.$refs.label.style.left = this.$refs.prefix.offsetWidth + 'px'; + this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px'; }, methods: { focus() { @@ -38,39 +38,18 @@ export default Vue.extend({ @import '~const.styl' .ui-input - padding-bottom 16px + margin-bottom 32px > .input display flex margin-top 16px - - &:before - content '' - display block - position absolute - bottom 0 - left 0 - right 0 - height 1px - background rgba(#000, 0.42) - - &:after - content '' - display block - position absolute - bottom 0 - left 0 - right 0 - height 2px - background $theme-color - opacity 0 - transform scaleX(0.12) - transition border 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) - will-change border opacity transform + padding 6px 12px + background #f5f5f5 + border-radius 6px > .label position absolute - top 0 + top 6px left 0 pointer-events none transition 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) @@ -85,6 +64,8 @@ export default Vue.extend({ flex 1 width 100% padding 0 + font inherit + font-weight bold font-size 16px line-height 32px background transparent @@ -110,9 +91,7 @@ export default Vue.extend({ &.focused > .input - &:after - opacity 1 - transform scaleX(1) + background #eee > .label color $theme-color @@ -121,7 +100,7 @@ export default Vue.extend({ &.filled > .input > .label - top -16px + top -20px left 0 !important font-size 12px line-height 20px diff --git a/src/client/app/mobile/script.ts b/src/client/app/mobile/script.ts index a6f4359432..8ee078d621 100644 --- a/src/client/app/mobile/script.ts +++ b/src/client/app/mobile/script.ts @@ -2,13 +2,11 @@ * Mobile Client */ -import Vue from 'vue'; import VueRouter from 'vue-router'; // Style import './style.styl'; import '../../element.scss'; -import '../../md.scss'; import init from '../init'; diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue index ceb1abb9a0..07891fd56b 100644 --- a/src/client/app/mobile/views/pages/welcome.vue +++ b/src/client/app/mobile/views/pages/welcome.vue @@ -1,27 +1,23 @@ <template> <div class="welcome"> <div> - <h1><b>Misskey</b>へようこそ</h1> - <p>Twitter風ミニブログSNS、Misskeyへようこそ。共有したいことを投稿したり、タイムラインでみんなの投稿を読むこともできます。<br><a href="/signup">アカウントを作成する</a></p> + <img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" alt="Misskey"> <div class="form"> - <p>%fa:lock% ログイン</p> + <form @submit.prevent="onSubmit"> + <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" placeholder="ユーザー名" 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> + <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-button type="submit" :disabled="signing">{{ signing ? 'ログインしています' : 'ログイン' }}</ui-button> + </form> <div> - <form @submit.prevent="onSubmit"> - <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" placeholder="ユーザー名" 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> - <span>パスワード</span> - <span slot="prefix">%fa:lock%</span> - </ui-input> - <ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" placeholder="トークン" required/> - <button type="submit" :disabled="signing">{{ signing ? 'ログインしています' : 'ログイン' }}</button> - </form> - <div> - <a :href="`${apiUrl}/signin/twitter`">Twitterでログイン</a> - </div> + <a :href="`${apiUrl}/signin/twitter`">Twitterでログイン</a> </div> </div> <div class="tl"> @@ -92,81 +88,44 @@ export default Vue.extend({ <style lang="stylus" scoped> .welcome - background linear-gradient(to bottom, #1e1d65, #bd6659) + background #fff > div padding 16px margin 0 auto max-width 500px - h1 - margin 0 - padding 8px - font-size 1.5em - font-weight normal - color #cacac3 - - & + p - margin 0 0 16px 0 - padding 0 8px 0 8px - color #949fa9 + > img + display block + max-width 200px + margin 0 auto .form margin-bottom 16px - background #fff - border solid 1px rgba(#000, 0.2) - border-radius 8px - overflow hidden - > p - margin 0 - padding 12px 20px - color #555 - background #f5f5f5 - border-bottom solid 1px #ddd + > form + padding 16px - > div - - > form - padding 16px - border-bottom solid 1px #ddd - - input - display block - padding 12px - margin 0 0 16px 0 - width 100% - font-size 1em - color rgba(#000, 0.7) - background #fff - outline none - border solid 1px #ddd - border-radius 4px - - button - display block - width 100% - padding 10px - margin 0 - color #333 - font-size 1em - text-align center - text-decoration none - text-shadow 0 1px 0 rgba(255, 255, 255, 0.9) - background-image linear-gradient(#fafafa, #eaeaea) - border 1px solid #ddd - border-bottom-color #cecece - border-radius 4px - - &:active - background-color #767676 - background-image none - border-color #444 - box-shadow 0 1px 3px rgba(#000, 0.075), inset 0 0 5px rgba(#000, 0.2) - - > div - padding 16px + button + display block + width 100% + padding 10px + margin 0 + color #333 + font-size 1em text-align center + text-decoration none + text-shadow 0 1px 0 rgba(255, 255, 255, 0.9) + background-image linear-gradient(#fafafa, #eaeaea) + border 1px solid #ddd + border-bottom-color #cecece + border-radius 4px + + &:active + background-color #767676 + background-image none + border-color #444 + box-shadow 0 1px 3px rgba(#000, 0.075), inset 0 0 5px rgba(#000, 0.2) > .tl background #fff From 3a4833818f67aec56bc3570088a1ef34466f3905 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Thu, 14 Jun 2018 09:51:55 +0900 Subject: [PATCH 03/11] wip --- .../views/components/material/button.vue | 3 +- .../views/components/material/input.vue | 43 ++++++++-- .../app/common/views/components/signup.vue | 54 ++++++------- src/client/app/mobile/views/pages/signup.vue | 41 ++-------- src/client/app/mobile/views/pages/welcome.vue | 80 +++++++++---------- 5 files changed, 109 insertions(+), 112 deletions(-) diff --git a/src/client/app/common/views/components/material/button.vue b/src/client/app/common/views/components/material/button.vue index 0c768cf4cc..8dacedbac6 100644 --- a/src/client/app/common/views/components/material/button.vue +++ b/src/client/app/common/views/components/material/button.vue @@ -1,6 +1,6 @@ <template> <div class="ui-button"> - <button> + <button :type="type"> <slot></slot> </button> </div> @@ -25,6 +25,7 @@ export default Vue.extend({ > button display block width 100% + margin 32px 0 16px 0 padding 0 color $theme-color-foreground font-weight bold diff --git a/src/client/app/common/views/components/material/input.vue b/src/client/app/common/views/components/material/input.vue index fe64354908..6564b3aa6c 100644 --- a/src/client/app/common/views/components/material/input.vue +++ b/src/client/app/common/views/components/material/input.vue @@ -3,16 +3,40 @@ <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" :value="value" @input="$emit('input', $event.target.value)" @focus="focused = true" @blur="focused = false"> + <input ref="input" + :type="type" + :value="value" + :required="required" + :readonly="readonly" + @input="$emit('input', $event.target.value)" + @focus="focused = true" + @blur="focused = false"> <div class="suffix" @click="focus"><slot name="suffix"></slot></div> </div> + <div class="text"><slot name="text"></slot></div> </div> </template> <script lang="ts"> import Vue from 'vue'; export default Vue.extend({ - props: ['value'], + props: { + value: { + required: false + }, + type: { + type: String, + required: false + }, + required: { + type: Boolean, + required: false + }, + readonly: { + type: Boolean, + required: false + } + }, data() { return { focused: false @@ -38,13 +62,13 @@ export default Vue.extend({ @import '~const.styl' .ui-input - margin-bottom 32px + margin-bottom 16px + padding-top 16px > .input display flex - margin-top 16px padding 6px 12px - background #f5f5f5 + background rgba(#000, 0.035) border-radius 6px > .label @@ -89,9 +113,16 @@ export default Vue.extend({ > .suffix padding-left 4px + > .text + margin 8px 0 + font-size 14px + + > p + margin 0 + &.focused > .input - background #eee + background rgba(#000, 0.05) > .label color $theme-color diff --git a/src/client/app/common/views/components/signup.vue b/src/client/app/common/views/components/signup.vue index f8bf7dd798..3adb10f2c3 100644 --- a/src/client/app/common/views/components/signup.vue +++ b/src/client/app/common/views/components/signup.vue @@ -1,20 +1,27 @@ <template> <form class="mk-signup" @submit.prevent="onSubmit" autocomplete="off"> <label class="username"> - <p class="caption">%fa:at%%i18n:@username%</p> - <input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" placeholder="a~z、A~Z、0~9、-" autocomplete="off" required @input="onChangeUsername"/> - <p class="profile-page-url-preview" v-if="shouldShowProfileUrl">{{ `${url}/@${username}` }}</p> - <p class="info" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw%%i18n:@checking%</p> - <p class="info" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw%%i18n:@available%</p> - <p class="info" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@unavailable%</p> - <p class="info" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@error%</p> - <p class="info" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@invalid-format%</p> - <p class="info" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@too-short%</p> - <p class="info" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@too-long%</p> + <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"> - <p class="caption">%fa:lock%%i18n:@password%</p> - <input v-model="password" type="password" placeholder="%i18n:@password-placeholder%" autocomplete="off" required @input="onChangePassword"/> + <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> </div> @@ -23,14 +30,15 @@ <p class="info" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw%%i18n:@strong-password%</p> </label> <label class="retype-password"> - <p class="caption">%fa:lock%%i18n:@password%(%i18n:@retype%)</p> - <input v-model="retypedPassword" type="password" placeholder="%i18n:@retype-placeholder%" autocomplete="off" required @input="onChangePasswordRetype"/> + <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"> - <p class="caption"><template v-if="recaptchaed">%fa:toggle-on%</template><template v-if="!recaptchaed">%fa:toggle-off%</template>%i18n:@recaptcha%</p> - <div class="g-recaptcha" data-callback="onRecaptchaed" data-expired-callback="onRecaptchaExpired" :data-sitekey="recaptchaSitekey"></div> + <div class="g-recaptcha" :data-sitekey="recaptchaSitekey"></div> </label> <label class="agree-tou"> <input name="agree-tou" type="checkbox" autocomplete="off" required/> @@ -43,18 +51,18 @@ <script lang="ts"> import Vue from 'vue'; const getPasswordStrength = require('syuilo-password-strength'); -import { url, docsUrl, lang, recaptchaSitekey } from '../../../config'; +import { host, url, docsUrl, lang, recaptchaSitekey } from '../../../config'; export default Vue.extend({ data() { return { + host, username: '', password: '', retypedPassword: '', url, touUrl: `${docsUrl}/${lang}/tou`, recaptchaSitekey, - recaptchaed: false, usernameState: null, passwordStrength: '', passwordRetypeState: null @@ -130,19 +138,9 @@ export default Vue.extend({ alert('%i18n:@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'); diff --git a/src/client/app/mobile/views/pages/signup.vue b/src/client/app/mobile/views/pages/signup.vue index b8245beb00..f2b29bca60 100644 --- a/src/client/app/mobile/views/pages/signup.vue +++ b/src/client/app/mobile/views/pages/signup.vue @@ -1,28 +1,18 @@ <template> <div class="signup"> <h1>Misskeyをはじめる</h1> - <p>いつでも、どこからでもMisskeyを利用できます。もちろん、無料です。</p> - <div class="form"> - <p>新規登録</p> - <div> - <mk-signup/> - </div> - </div> + <mk-signup/> </div> </template> <script lang="ts"> import Vue from 'vue'; -export default Vue.extend({ - mounted() { - document.documentElement.style.background = '#293946'; - } -}); +export default Vue.extend({}); </script> <style lang="stylus" scoped> .signup - padding 16px + padding 32px margin 0 auto max-width 500px @@ -30,28 +20,7 @@ export default Vue.extend({ margin 0 padding 8px font-size 1.5em - font-weight normal - color #c3c6ca - - & + p - margin 0 0 16px 0 - padding 0 8px 0 8px - color #949fa9 - - .form - background #fff - border solid 1px rgba(#000, 0.2) - border-radius 8px - overflow hidden - - > p - margin 0 - padding 12px 20px - color #555 - background #f5f5f5 - border-bottom solid 1px #ddd - - > div - padding 16px + font-weight bold + color #444 </style> diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue index 07891fd56b..01b20aa472 100644 --- a/src/client/app/mobile/views/pages/welcome.vue +++ b/src/client/app/mobile/views/pages/welcome.vue @@ -2,7 +2,13 @@ <div class="welcome"> <div> <img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" alt="Misskey"> - <div class="form"> + <p class="host">{{ host }}</p> + <div class="about"> + <h2>{{ name || 'unidentified' }}</h2> + <p v-html="description || '%i18n:common.about%'"></p> + <router-link class="signup" to="/signup">新規登録</router-link> + </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"> <span>ユーザー名</span> @@ -20,13 +26,6 @@ <a :href="`${apiUrl}/signin/twitter`">Twitterでログイン</a> </div> </div> - <div class="tl"> - <p>%fa:comments R% タイムラインを見てみる</p> - <mk-welcome-timeline/> - </div> - <div class="users"> - <mk-avatar class="avatar" v-for="user in users" :key="user.id" :user="user"/> - </div> <footer> <small>{{ copyright }}</small> </footer> @@ -88,10 +87,11 @@ export default Vue.extend({ <style lang="stylus" scoped> .welcome - background #fff + text-align center + //background #fff > div - padding 16px + padding 32px margin 0 auto max-width 500px @@ -100,11 +100,36 @@ export default Vue.extend({ max-width 200px margin 0 auto - .form - margin-bottom 16px + > .host + display block + text-align center + padding 6px 12px + line-height 32px + font-weight bold + color #333 + background rgba(#000, 0.035) + border-radius 6px + + > .about + margin-top 16px + padding 16px + color #444 + background #fff + border-radius 6px + + > h2 + margin 0 + + > p + margin 8px + + > .signup + font-weight bold + + > .login + margin 16px 0 > form - padding 16px button display block @@ -127,36 +152,9 @@ export default Vue.extend({ border-color #444 box-shadow 0 1px 3px rgba(#000, 0.075), inset 0 0 5px rgba(#000, 0.2) - > .tl - background #fff - border solid 1px rgba(#000, 0.2) - border-radius 8px - overflow hidden - - > p - margin 0 - padding 12px 20px - color #555 - background #f5f5f5 - border-bottom solid 1px #ddd - - > .mk-welcome-timeline - max-height 300px - overflow auto - - > .users - margin 12px 0 0 0 - - > * - display inline-block - margin 4px - width 38px - height 38px - border-radius 6px - > footer text-align center - color #fff + color #444 > small display block 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 04/11] 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 From 120c11b1817429c762d54df865b8cf1a35bf4e08 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Thu, 14 Jun 2018 16:48:49 +0900 Subject: [PATCH 05/11] wip --- .../app/common/views/components/index.ts | 4 +- .../components/ui/{group.vue => card.vue} | 11 ++- .../app/common/views/components/ui/form.vue | 2 + .../app/common/views/components/ui/switch.vue | 80 +++++-------------- .../app/mobile/views/pages/settings.vue | 31 ++++--- .../views/pages/settings/settings.profile.vue | 6 +- 6 files changed, 51 insertions(+), 83 deletions(-) rename src/client/app/common/views/components/ui/{group.vue => card.vue} (56%) diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index 060af388b3..0e20e66f5a 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -31,7 +31,7 @@ import Othello from './othello.vue'; import welcomeTimeline from './welcome-timeline.vue'; import uiInput from './ui/input.vue'; import uiButton from './ui/button.vue'; -import uiGroup from './ui/group.vue'; +import uiCard from './ui/card.vue'; import uiForm from './ui/form.vue'; import uiTextarea from './ui/textarea.vue'; import uiSwitch from './ui/switch.vue'; @@ -67,7 +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-card', uiCard); Vue.component('ui-form', uiForm); Vue.component('ui-textarea', uiTextarea); Vue.component('ui-switch', uiSwitch); diff --git a/src/client/app/common/views/components/ui/group.vue b/src/client/app/common/views/components/ui/card.vue similarity index 56% rename from src/client/app/common/views/components/ui/group.vue rename to src/client/app/common/views/components/ui/card.vue index fb29458ce8..5ba15dad7d 100644 --- a/src/client/app/common/views/components/ui/group.vue +++ b/src/client/app/common/views/components/ui/card.vue @@ -1,5 +1,5 @@ <template> -<div class="ui-group"> +<div class="ui-card"> <header> <slot name="title"></slot> </header> @@ -16,8 +16,15 @@ export default Vue.extend({}); <style lang="stylus" scoped> @import '~const.styl' -.ui-group +.ui-card + margin 16px 0 + padding 32px + background #fff + //box-shadow 0 3px 1px -2px rgba(#000, 0.2), 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12) + > header font-weight bold + font-size 28px + color #444 </style> diff --git a/src/client/app/common/views/components/ui/form.vue b/src/client/app/common/views/components/ui/form.vue index 0893af1bce..b6b4a76d2a 100644 --- a/src/client/app/common/views/components/ui/form.vue +++ b/src/client/app/common/views/components/ui/form.vue @@ -23,6 +23,8 @@ export default Vue.extend({ .ui-form > fieldset + margin 0 + padding 0 border none </style> diff --git a/src/client/app/common/views/components/ui/switch.vue b/src/client/app/common/views/components/ui/switch.vue index 2cac6262f1..e78951a352 100644 --- a/src/client/app/common/views/components/ui/switch.vue +++ b/src/client/app/common/views/components/ui/switch.vue @@ -16,7 +16,7 @@ @keydown.enter="switchValue" > <span class="button"> - <span :style="{ transform }"></span> + <span></span> </span> <span class="label"> <span :aria-hidden="!checked"><slot></slot></span> @@ -48,9 +48,6 @@ export default Vue.extend({ computed: { checked(): boolean { return this.value; - }, - transform(): string { - return this.checked ? 'translate3d(14px, 0, 0)' : ''; } }, watch: { @@ -88,7 +85,7 @@ export default Vue.extend({ root(isDark) display flex - margin 16px 0 + margin 32px 0 cursor pointer transition all 0.3s @@ -101,31 +98,12 @@ root(isDark) &.checked > .button - background-color $theme-color - border-color $theme-color + background-color rgba($theme-color, 0.4) + border-color rgba($theme-color, 0.4) - > .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 + > * + background-color $theme-color + transform translateX(14px) > input position absolute @@ -134,42 +112,26 @@ root(isDark) 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 + margin 3px 0 0 0 + width 34px + height 14px + background isDark ? rgba(#fff, 0.1) : rgba(#000, 0.05) outline none - border-radius 6px + border-radius 14px transition inherit > * position absolute - top 1px - left 1px - border-radius 6px - transition transform 0.3s - width 28px - height 28px + top -3px + left 0 + border-radius 100% + transition background-color 0.3s, transform 0.3s + width 20px + height 20px background-color #fff + box-shadow 0 2px 1px -1px rgba(#000, 0.2), 0 1px 1px 0 rgba(#000, 0.14), 0 1px 3px 0 rgba(#000, 0.12) > .label margin-left 8px @@ -180,9 +142,9 @@ root(isDark) > span display block - line-height 32px + line-height 20px font-weight bold - color isDark ? #c4ccd2 : #4a535a + color isDark ? #c4ccd2 : rgba(#000, 0.75) transition inherit > p diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue index 716f7afc0c..25cfbf732b 100644 --- a/src/client/app/mobile/views/pages/settings.vue +++ b/src/client/app/mobile/views/pages/settings.vue @@ -6,7 +6,7 @@ <div> <x-profile/> - <ui-group> + <ui-card> <div slot="title">%fa:palette% %i18n:@design%</div> <div> @@ -39,9 +39,9 @@ <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> + </ui-card> - <ui-group> + <ui-card> <div slot="title">%fa:cog% %i18n:@behavior%</div> <div> @@ -63,9 +63,9 @@ <div> <ui-switch v-model="lightmode">%i18n:@i-am-under-limited-internet%</ui-switch> </div> - </ui-group> + </ui-card> - <ui-group> + <ui-card> <div slot="title">%fa:language% %i18n:@lang%</div> <md-field> @@ -80,9 +80,9 @@ </md-select> </md-field> <span class="md-helper-text">%fa:info-circle% %i18n:@lang-tip%</span> - </ui-group> + </ui-card> - <ui-group> + <ui-card> <div slot="title">%fa:B twitter% %i18n:@twitter%</div> <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> @@ -91,9 +91,9 @@ <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> + </ui-card> - <ui-group> + <ui-card> <div slot="title">%fa:sync-alt% %i18n:@update%</div> <div>%i18n:@version% <i>{{ version }}</i></div> @@ -104,7 +104,7 @@ <template v-if="checkingForUpdate">%i18n:@update-checking%<mk-ellipsis/></template> <template v-else>%i18n:@check-for-updates%</template> </md-button> - </ui-group> + </ui-card> </div> <p><small>ver {{ version }} ({{ codename }})</small></p> </main> @@ -247,20 +247,17 @@ export default Vue.extend({ <style lang="stylus" scoped> root(isDark) - padding 0 16px margin 0 auto max-width 500px width 100% - > div - > * - margin-bottom 16px - > p display block - margin 24px + margin 16px 0 + padding 16px text-align center - color isDark ? #cad2da : #a2a9b1 + color isDark ? #cad2da : #2c662d + background #fcfff5 main[data-darkmode] root(true) 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 73d876d14e..de891b5736 100644 --- a/src/client/app/mobile/views/pages/settings/settings.profile.vue +++ b/src/client/app/mobile/views/pages/settings/settings.profile.vue @@ -1,6 +1,6 @@ <template> -<ui-group> - <div slot="title">%fa:pencil-alt% %i18n:@title%</div> +<ui-card> + <div slot="title">%fa:user% %i18n:@title%</div> <ui-form :disabled="saving"> <ui-input v-model="name" :max="30"> @@ -41,7 +41,7 @@ <ui-button @click="save">%i18n:@save%</ui-button> </ui-form> -</ui-group> +</ui-card> </template> <script lang="ts"> From c5e9b69eb3b235e9828371affe0d8d88a780d096 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Thu, 14 Jun 2018 18:53:02 +0900 Subject: [PATCH 06/11] wip --- .../app/common/views/components/ui/card.vue | 14 +- .../app/common/views/components/ui/input.vue | 147 +++++++++++++++--- .../app/common/views/components/ui/switch.vue | 1 - .../common/views/components/ui/textarea.vue | 56 ++++++- .../views/pages/settings/settings.profile.vue | 4 +- 5 files changed, 188 insertions(+), 34 deletions(-) diff --git a/src/client/app/common/views/components/ui/card.vue b/src/client/app/common/views/components/ui/card.vue index 5ba15dad7d..97f06ca655 100644 --- a/src/client/app/common/views/components/ui/card.vue +++ b/src/client/app/common/views/components/ui/card.vue @@ -10,17 +10,23 @@ <script lang="ts"> import Vue from 'vue'; -export default Vue.extend({}); +export default Vue.extend({ + provide() { + return { + isCardChild: true + }; + } +}); </script> <style lang="stylus" scoped> @import '~const.styl' .ui-card - margin 16px 0 - padding 32px + margin 16px + padding 16px background #fff - //box-shadow 0 3px 1px -2px rgba(#000, 0.2), 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12) + box-shadow 0 3px 1px -2px rgba(#000, 0.2), 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12) > header font-weight bold diff --git a/src/client/app/common/views/components/ui/input.vue b/src/client/app/common/views/components/ui/input.vue index 7461aac7fe..3a474f0243 100644 --- a/src/client/app/common/views/components/ui/input.vue +++ b/src/client/app/common/views/components/ui/input.vue @@ -1,21 +1,35 @@ <template> -<div class="ui-input" :class="{ focused, filled }"> +<div class="ui-input" :class="[{ focused, filled }, styl]"> + <div class="icon" ref="icon"><slot name="icon"></slot></div> <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"> + <template v-if="type != 'file'"> + <input ref="input" + :type="type" + :value="v" + :required="required" + :readonly="readonly" + :pattern="pattern" + :autocomplete="autocomplete" + @input="$emit('input', $event.target.value)" + @focus="focused = true" + @blur="focused = false"> + </template> + <template v-else> + <input ref="input" + type="text" + :value="placeholder" + readonly + @click="chooseFile"> + <input ref="file" + type="file" + :value="value" + @change="onChangeFile"> + </template> <div class="suffix"><slot name="suffix"></slot></div> </div> <div class="text"><slot name="text"></slot></div> @@ -59,17 +73,34 @@ export default Vue.extend({ }, data() { return { + v: this.value, focused: false, - passwordStrength: '' - } + passwordStrength: '', + styl: 'fill' + }; }, computed: { filled(): boolean { - return this.value != '' && this.value != null; + return this.v != '' && this.v != null; + }, + placeholder(): string { + if (this.type != 'file') return null; + if (this.v == null) return null; + + if (typeof this.v == 'string') return this.v; + + if (Array.isArray(this.v)) { + return this.v.map(file => file.name).join(', '); + } else { + return this.v.name; + } } }, watch: { value(v) { + this.v = v; + }, + v(v) { if (this.withPasswordMeter) { if (v == '') { this.passwordStrength = ''; @@ -82,6 +113,12 @@ export default Vue.extend({ } } }, + inject: ['isCardChild'], + created() { + if (this.isCardChild) { + this.styl = 'line'; + } + }, mounted() { if (this.$refs.prefix) { this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px'; @@ -90,6 +127,14 @@ export default Vue.extend({ methods: { focus() { this.$refs.input.focus(); + }, + chooseFile() { + this.$refs.file.click(); + }, + onChangeFile() { + this.v = Array.from((this.$refs.file as any).files); + this.$emit('input', this.v); + this.$emit('change', this.v); } } }); @@ -98,14 +143,52 @@ export default Vue.extend({ <style lang="stylus" scoped> @import '~const.styl' -.ui-input +root(isDark, fill) margin 32px 0 + > .icon + position absolute + top 0 + left 0 + width 24px + text-align center + line-height 32px + color rgba(#000, 0.54) + + &:not(:empty) + .input + margin-left 28px + > .input display flex - padding 6px 12px - background rgba(#000, 0.035) - border-radius 6px + + if fill + padding 6px 12px + background rgba(#000, 0.035) + border-radius 6px + else + &:before + content '' + display block + position absolute + bottom 0 + left 0 + right 0 + height 1px + background rgba(#000, 0.42) + + &:after + content '' + display block + position absolute + bottom 0 + left 0 + right 0 + height 2px + background $theme-color + opacity 0 + transform scaleX(0.12) + transition border 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) + will-change border opacity transform > .password-meter position absolute @@ -142,7 +225,7 @@ export default Vue.extend({ > .label position absolute - top 6px + top fill ? 6px : 0 left 0 pointer-events none transition 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) @@ -161,7 +244,7 @@ export default Vue.extend({ width 100% padding 0 font inherit - font-weight bold + font-weight fill ? bold : normal font-size 16px line-height 32px background transparent @@ -170,6 +253,9 @@ export default Vue.extend({ outline none box-shadow none + &[type='file'] + display none + > .prefix > .suffix display block @@ -199,7 +285,12 @@ export default Vue.extend({ &.focused > .input - background rgba(#000, 0.05) + if fill + background rgba(#000, 0.05) + else + &:after + opacity 1 + transform scaleX(1) > .label color $theme-color @@ -208,8 +299,20 @@ export default Vue.extend({ &.filled > .input > .label - top -24px + top fill ? -24px : -16px left 0 !important transform scale(0.8) +.ui-input[data-darkmode] + &.fill + root(true, true) + &:not(.fill) + root(true, false) + +.ui-input:not([data-darkmode]) + &.fill + root(false, true) + &:not(.fill) + root(false, false) + </style> diff --git a/src/client/app/common/views/components/ui/switch.vue b/src/client/app/common/views/components/ui/switch.vue index e78951a352..f860309867 100644 --- a/src/client/app/common/views/components/ui/switch.vue +++ b/src/client/app/common/views/components/ui/switch.vue @@ -143,7 +143,6 @@ root(isDark) > span display block line-height 20px - font-weight bold color isDark ? #c4ccd2 : rgba(#000, 0.75) transition inherit diff --git a/src/client/app/common/views/components/ui/textarea.vue b/src/client/app/common/views/components/ui/textarea.vue index 0a9f60f1bc..d5e2b15628 100644 --- a/src/client/app/common/views/components/ui/textarea.vue +++ b/src/client/app/common/views/components/ui/textarea.vue @@ -65,13 +65,43 @@ export default Vue.extend({ <style lang="stylus" scoped> @import '~const.styl' -.ui-textarea +root(isDark, fill) margin 32px 0 > .input padding 12px - background rgba(#000, 0.035) - border-radius 6px + + if fill + background rgba(#000, 0.035) + border-radius 6px + else + &:before + content '' + display block + position absolute + top 0 + bottom 0 + left 0 + right 0 + background none + border solid 1px rgba(#000, 0.42) + border-radius 3px + pointer-events none + + &:after + content '' + display block + position absolute + top 0 + bottom 0 + left 0 + right 0 + background none + border solid 2px $theme-color + border-radius 3px + opacity 0 + transition opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1) + pointer-events none > .label position absolute @@ -94,7 +124,7 @@ export default Vue.extend({ min-height 100px padding 0 font inherit - font-weight bold + font-weight fill ? bold : normal font-size 16px background transparent border none @@ -111,7 +141,11 @@ export default Vue.extend({ &.focused > .input - background rgba(#000, 0.05) + if fill + background rgba(#000, 0.05) + else + &:after + opacity 1 > .label color $theme-color @@ -124,4 +158,16 @@ export default Vue.extend({ left 0 !important transform scale(0.8) +.ui-textarea[data-darkmode] + &.fill + root(true, true) + &:not(.fill) + root(true, false) + +.ui-textarea:not([data-darkmode]) + &.fill + root(false, true) + &:not(.fill) + root(false, false) + </style> 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 de891b5736..64adac01e6 100644 --- a/src/client/app/mobile/views/pages/settings/settings.profile.vue +++ b/src/client/app/mobile/views/pages/settings/settings.profile.vue @@ -29,12 +29,12 @@ <ui-input type="file" @change="onAvatarChange"> <span>%i18n:@avatar%</span> - <span slot="prefix">%fa:picture-o%</span> + <span slot="icon">%fa:image%</span> </ui-input> <ui-input type="file" @change="onBannerChange"> <span>%i18n:@banner%</span> - <span slot="prefix">%fa:picture-o%</span> + <span slot="icon">%fa:image%</span> </ui-input> <ui-switch v-model="isCat">%i18n:@is-cat%</ui-switch> From 11e95ea092e2c1e5d8ee3defba3a8a211cc65864 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Thu, 14 Jun 2018 18:57:54 +0900 Subject: [PATCH 07/11] wip --- .../app/common/views/components/ui/button.vue | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/src/client/app/common/views/components/ui/button.vue b/src/client/app/common/views/components/ui/button.vue index 57747fd469..7723c83f57 100644 --- a/src/client/app/common/views/components/ui/button.vue +++ b/src/client/app/common/views/components/ui/button.vue @@ -14,6 +14,17 @@ export default Vue.extend({ type: String, required: false } + }, + data() { + return { + styl: 'fill' + }; + }, + inject: ['isCardChild'], + created() { + if (this.isCardChild) { + this.styl = 'line'; + } } }); </script> @@ -21,26 +32,49 @@ export default Vue.extend({ <style lang="stylus" scoped> @import '~const.styl' -.ui-button +root(isDark, fill) > button display block width 100% margin 0 padding 0 - color $theme-color-foreground font-weight bold font-size 16px line-height 44px - background $theme-color border none border-radius 6px outline none box-shadow none - &:hover - background lighten($theme-color, 5%) + if fill + color $theme-color-foreground + background $theme-color - &:active - background darken($theme-color, 5%) + &:hover + background lighten($theme-color, 5%) + + &:active + background darken($theme-color, 5%) + else + color $theme-color + background none + + &:hover + color darken($theme-color, 5%) + + &:active + background rgba($theme-color, 0.3) + +.ui-button[data-darkmode] + &.fill + root(true, true) + &:not(.fill) + root(true, false) + +.ui-button:not([data-darkmode]) + &.fill + root(false, true) + &:not(.fill) + root(false, false) </style> From dec7d537dca22f60ddc595c7fc34eabaca2c13f1 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Thu, 14 Jun 2018 20:23:50 +0900 Subject: [PATCH 08/11] wip --- .../app/common/views/components/index.ts | 4 + .../app/common/views/components/ui/radio.vue | 120 ++++++++++ .../app/common/views/components/ui/select.vue | 212 ++++++++++++++++++ .../app/common/views/components/ui/switch.vue | 2 +- .../app/mobile/views/pages/settings.vue | 22 +- 5 files changed, 347 insertions(+), 13 deletions(-) create mode 100644 src/client/app/common/views/components/ui/radio.vue create mode 100644 src/client/app/common/views/components/ui/select.vue diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index 0e20e66f5a..b91008f718 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -35,6 +35,8 @@ import uiCard from './ui/card.vue'; import uiForm from './ui/form.vue'; import uiTextarea from './ui/textarea.vue'; import uiSwitch from './ui/switch.vue'; +import uiRadio from './ui/radio.vue'; +import uiSelect from './ui/select.vue'; Vue.component('mk-analog-clock', analogClock); Vue.component('mk-menu', menu); @@ -71,3 +73,5 @@ Vue.component('ui-card', uiCard); Vue.component('ui-form', uiForm); Vue.component('ui-textarea', uiTextarea); Vue.component('ui-switch', uiSwitch); +Vue.component('ui-radio', uiRadio); +Vue.component('ui-select', uiSelect); diff --git a/src/client/app/common/views/components/ui/radio.vue b/src/client/app/common/views/components/ui/radio.vue new file mode 100644 index 0000000000..2b7f1d9dd4 --- /dev/null +++ b/src/client/app/common/views/components/ui/radio.vue @@ -0,0 +1,120 @@ +<template> +<div + class="ui-radio" + :class="{ disabled, checked }" + :aria-checked="checked" + :aria-disabled="disabled" + @click="toggle" +> + <input type="radio" + :disabled="disabled" + > + <span class="button"> + <span></span> + </span> + <span class="label"><slot></slot></span> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +export default Vue.extend({ + model: { + prop: 'model', + event: 'change' + }, + props: { + model: { + type: String, + required: false + }, + value: { + type: String, + required: false + }, + disabled: { + type: Boolean, + default: false + } + }, + computed: { + checked(): boolean { + return this.model === this.value; + } + }, + methods: { + toggle() { + this.$emit('change', this.value); + } + } +}); +</script> + +<style lang="stylus" scoped> +@import '~const.styl' + +root(isDark) + display inline-block + margin 32px 32px 32px 0 + cursor pointer + transition all 0.3s + + > * + user-select none + + &.disabled + opacity 0.6 + cursor not-allowed + + &.checked + > .button + border-color $theme-color + + &:after + background-color $theme-color + transform scale(1) + opacity 1 + + > input + position absolute + width 0 + height 0 + opacity 0 + margin 0 + + > .button + position absolute + width 20px + height 20px + background none + border solid 2px rgba(#000, 0.54) + border-radius 100% + transition inherit + + &:after + content '' + display block + position absolute + top 3px + right 3px + bottom 3px + left 3px + border-radius 100% + opacity 0 + transform scale(0) + transition 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) + + > .label + margin-left 28px + display block + font-size 16px + line-height 20px + cursor pointer + +.ui-radio[data-darkmode] + root(true) + +.ui-radio:not([data-darkmode]) + root(false) + +</style> diff --git a/src/client/app/common/views/components/ui/select.vue b/src/client/app/common/views/components/ui/select.vue new file mode 100644 index 0000000000..c56ae86159 --- /dev/null +++ b/src/client/app/common/views/components/ui/select.vue @@ -0,0 +1,212 @@ +<template> +<div class="ui-select" :class="[{ focused, filled }, styl]"> + <div class="icon" ref="icon"><slot name="icon"></slot></div> + <div class="input" @click="focus"> + <span class="label" ref="label"><slot name="label"></slot></span> + <div class="prefix" ref="prefix"><slot name="prefix"></slot></div> + <select ref="input" + :value="v" + :required="required" + @input="$emit('input', $event.target.value)" + @focus="focused = true" + @blur="focused = false"> + <slot></slot> + </select> + <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'; + +export default Vue.extend({ + props: { + value: { + required: false + }, + required: { + type: Boolean, + required: false + } + }, + data() { + return { + v: this.value, + focused: false, + styl: 'fill' + }; + }, + computed: { + filled(): boolean { + return this.v != '' && this.v != null; + } + }, + watch: { + value(v) { + this.v = v; + } + }, + inject: ['isCardChild'], + created() { + if (this.isCardChild) { + this.styl = 'line'; + } + }, + 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' + +root(isDark, fill) + margin 32px 0 + + > .icon + position absolute + top 0 + left 0 + width 24px + text-align center + line-height 32px + color rgba(#000, 0.54) + + &:not(:empty) + .input + margin-left 28px + + > .input + display flex + + if fill + padding 6px 12px + background rgba(#000, 0.035) + border-radius 6px + else + &:before + content '' + display block + position absolute + bottom 0 + left 0 + right 0 + height 1px + background rgba(#000, 0.42) + + &:after + content '' + display block + position absolute + bottom 0 + left 0 + right 0 + height 2px + background $theme-color + opacity 0 + transform scaleX(0.12) + transition border 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) + will-change border opacity transform + + > .label + position absolute + top fill ? 6px : 0 + 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) + + > select + display block + flex 1 + width 100% + padding 0 + font inherit + font-weight fill ? bold : normal + font-size 16px + height 32px + background transparent + border none + border-radius 0 + outline none + box-shadow none + + &[type='file'] + display 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 + if fill + background rgba(#000, 0.05) + else + &:after + opacity 1 + transform scaleX(1) + + > .label + color $theme-color + + &.focused + &.filled + > .input + > .label + top fill ? -24px : -16px + left 0 !important + transform scale(0.8) + +.ui-select[data-darkmode] + &.fill + root(true, true) + &:not(.fill) + root(true, false) + +.ui-select:not([data-darkmode]) + &.fill + root(false, true) + &:not(.fill) + root(false, false) + +</style> diff --git a/src/client/app/common/views/components/ui/switch.vue b/src/client/app/common/views/components/ui/switch.vue index f860309867..2431a76528 100644 --- a/src/client/app/common/views/components/ui/switch.vue +++ b/src/client/app/common/views/components/ui/switch.vue @@ -117,7 +117,7 @@ root(isDark) margin 3px 0 0 0 width 34px height 14px - background isDark ? rgba(#fff, 0.1) : rgba(#000, 0.05) + background isDark ? rgba(#fff, 0.1) : rgba(#000, 0.07) outline none border-radius 14px transition inherit diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue index 25cfbf732b..beac788482 100644 --- a/src/client/app/mobile/views/pages/settings.vue +++ b/src/client/app/mobile/views/pages/settings.vue @@ -36,8 +36,8 @@ <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> + <ui-radio v-model="postStyle" value="standard">%i18n:@post-style-standard%</ui-radio> + <ui-radio v-model="postStyle" value="smart">%i18n:@post-style-smart%</ui-radio> </div> </ui-card> @@ -68,17 +68,15 @@ <ui-card> <div slot="title">%fa:language% %i18n:@lang%</div> - <md-field> - <md-select v-model="lang" placeholder="%i18n:@auto%"> - <md-optgroup label="%i18n:@recommended%"> - <md-option value="">%i18n:@auto%</md-option> - </md-optgroup> + <ui-select v-model="lang" placeholder="%i18n:@auto%"> + <optgroup label="%i18n:@recommended%"> + <option value="">%i18n:@auto%</option> + </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> + <optgroup label="%i18n:@specify-language%"> + <option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option> + </optgroup> + </ui-select> <span class="md-helper-text">%fa:info-circle% %i18n:@lang-tip%</span> </ui-card> From d90f75425f0449bcb04e462250a4495b63be39a0 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Thu, 14 Jun 2018 21:38:39 +0900 Subject: [PATCH 09/11] wip --- .../app/common/views/components/ui/card.vue | 16 ++++--- .../app/common/views/components/ui/input.vue | 13 +++--- .../app/common/views/components/ui/select.vue | 4 +- .../app/common/views/components/ui/switch.vue | 43 ++++--------------- .../common/views/components/ui/textarea.vue | 7 +-- 5 files changed, 33 insertions(+), 50 deletions(-) diff --git a/src/client/app/common/views/components/ui/card.vue b/src/client/app/common/views/components/ui/card.vue index 97f06ca655..e2b15240e4 100644 --- a/src/client/app/common/views/components/ui/card.vue +++ b/src/client/app/common/views/components/ui/card.vue @@ -22,15 +22,21 @@ export default Vue.extend({ <style lang="stylus" scoped> @import '~const.styl' -.ui-card +root(isDark) margin 16px padding 16px - background #fff + background isDark ? #282C37 : #fff box-shadow 0 3px 1px -2px rgba(#000, 0.2), 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12) > header - font-weight bold - font-size 28px - color #444 + font-weight normal + font-size 24px + color isDark ? #fff : #444 + +.ui-card[data-darkmode] + root(true) + +.ui-card:not([data-darkmode]) + root(false) </style> diff --git a/src/client/app/common/views/components/ui/input.vue b/src/client/app/common/views/components/ui/input.vue index 3a474f0243..167dd4e2a9 100644 --- a/src/client/app/common/views/components/ui/input.vue +++ b/src/client/app/common/views/components/ui/input.vue @@ -153,7 +153,7 @@ root(isDark, fill) width 24px text-align center line-height 32px - color rgba(#000, 0.54) + color isDark ? rgba(#fff, 0.7) : rgba(#000, 0.54) &:not(:empty) + .input margin-left 28px @@ -174,7 +174,7 @@ root(isDark, fill) left 0 right 0 height 1px - background rgba(#000, 0.42) + background isDark ? rgba(#fff, 0.7) : rgba(#000, 0.42) &:after content '' @@ -232,7 +232,7 @@ root(isDark, fill) transition-duration 0.3s font-size 16px line-height 32px - color rgba(#000, 0.54) + color isDark ? rgba(#fff, 0.7) : rgba(#000, 0.54) pointer-events none //will-change transform transform-origin top left @@ -247,6 +247,7 @@ root(isDark, fill) font-weight fill ? bold : normal font-size 16px line-height 32px + color isDark ? #fff : #000 background transparent border none border-radius 0 @@ -263,7 +264,7 @@ root(isDark, fill) justify-self center font-size 16px line-height 32px - color rgba(#000, 0.54) + color isDark ? rgba(#fff, 0.7) : rgba(#000, 0.54) pointer-events none > * @@ -299,9 +300,9 @@ root(isDark, fill) &.filled > .input > .label - top fill ? -24px : -16px + top fill ? -24px : -17px left 0 !important - transform scale(0.8) + transform scale(0.75) .ui-input[data-darkmode] &.fill diff --git a/src/client/app/common/views/components/ui/select.vue b/src/client/app/common/views/components/ui/select.vue index c56ae86159..4577a15f68 100644 --- a/src/client/app/common/views/components/ui/select.vue +++ b/src/client/app/common/views/components/ui/select.vue @@ -193,9 +193,9 @@ root(isDark, fill) &.filled > .input > .label - top fill ? -24px : -16px + top fill ? -24px : -17px left 0 !important - transform scale(0.8) + transform scale(0.75) .ui-select[data-darkmode] &.fill diff --git a/src/client/app/common/views/components/ui/switch.vue b/src/client/app/common/views/components/ui/switch.vue index 2431a76528..24611b9aa0 100644 --- a/src/client/app/common/views/components/ui/switch.vue +++ b/src/client/app/common/views/components/ui/switch.vue @@ -5,15 +5,13 @@ role="switch" :aria-checked="checked" :aria-disabled="disabled" - @click="switchValue" - @mouseover="mouseenter" + @click="toggle" > <input type="checkbox" - @change="handleChange" ref="input" :disabled="disabled" - @keydown.enter="switchValue" + @keydown.enter="toggle" > <span class="button"> <span></span> @@ -30,6 +28,10 @@ <script lang="ts"> import Vue from 'vue'; export default Vue.extend({ + model: { + prop: 'value', + event: 'change' + }, props: { value: { type: Boolean, @@ -39,42 +41,15 @@ export default Vue.extend({ type: Boolean, default: false } - },/* - created() { - if (!~[true, false].indexOf(this.value)) { - this.$emit('input', false); - } - },*/ + }, computed: { checked(): boolean { return this.value; } }, - 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); + toggle() { 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(); } } }); @@ -117,7 +92,7 @@ root(isDark) margin 3px 0 0 0 width 34px height 14px - background isDark ? rgba(#fff, 0.1) : rgba(#000, 0.07) + background isDark ? rgba(#fff, 0.1) : rgba(#000, 0.25) outline none border-radius 14px transition inherit diff --git a/src/client/app/common/views/components/ui/textarea.vue b/src/client/app/common/views/components/ui/textarea.vue index d5e2b15628..cc6b376ead 100644 --- a/src/client/app/common/views/components/ui/textarea.vue +++ b/src/client/app/common/views/components/ui/textarea.vue @@ -84,7 +84,7 @@ root(isDark, fill) left 0 right 0 background none - border solid 1px rgba(#000, 0.42) + border solid 1px isDark ? rgba(#fff, 0.7) : rgba(#000, 0.42) border-radius 3px pointer-events none @@ -112,7 +112,7 @@ root(isDark, fill) transition-duration 0.3s font-size 16px line-height 32px - color rgba(#000, 0.54) + color isDark ? rgba(#fff, 0.7) : rgba(#000, 0.54) pointer-events none //will-change transform transform-origin top left @@ -126,6 +126,7 @@ root(isDark, fill) font inherit font-weight fill ? bold : normal font-size 16px + color isDark ? #fff : #000 background transparent border none border-radius 0 @@ -156,7 +157,7 @@ root(isDark, fill) > .label top -24px left 0 !important - transform scale(0.8) + transform scale(0.75) .ui-textarea[data-darkmode] &.fill From 0ac9120064b295a363b74a2c2afc487db2b50908 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Fri, 15 Jun 2018 07:56:56 +0900 Subject: [PATCH 10/11] wip --- .../app/common/views/components/signup.vue | 10 +-- .../app/common/views/components/ui/button.vue | 8 +- .../app/common/views/components/ui/card.vue | 4 + .../app/common/views/components/ui/form.vue | 2 +- .../app/common/views/components/ui/input.vue | 8 +- .../app/common/views/components/ui/radio.vue | 2 +- .../app/common/views/components/ui/select.vue | 11 ++- .../app/common/views/components/ui/switch.vue | 2 +- src/client/app/config.ts | 4 + .../app/mobile/views/pages/settings.vue | 79 +++++++------------ .../views/pages/settings/settings.profile.vue | 17 ++-- src/client/app/mobile/views/pages/welcome.vue | 6 +- src/config/types.ts | 2 + webpack.config.ts | 2 + 14 files changed, 80 insertions(+), 77 deletions(-) diff --git a/src/client/app/common/views/components/signup.vue b/src/client/app/common/views/components/signup.vue index d1621a4848..987cc7e52d 100644 --- a/src/client/app/common/views/components/signup.vue +++ b/src/client/app/common/views/components/signup.vue @@ -1,6 +1,6 @@ <template> -<form class="mk-signup" @submit.prevent="onSubmit" autocomplete="off"> - <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" autocomplete="off" required @input="onChangeUsername"> +<form class="mk-signup" @submit.prevent="onSubmit" :autocomplete="Math.random()"> + <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" required @input="onChangeUsername"> <span>%i18n:@username%</span> <span slot="prefix">@</span> <span slot="suffix">@{{ host }}</span> @@ -12,7 +12,7 @@ <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"> + <ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true"> <span>%i18n:@password%</span> <span slot="prefix">%fa:lock%</span> <div slot="text"> @@ -21,7 +21,7 @@ <p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p> </div> </ui-input> - <ui-input v-model="retypedPassword" type="password" autocomplete="off" required @input="onChangePasswordRetype"> + <ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype"> <span>%i18n:@password% (%i18n:@retype%)</span> <span slot="prefix">%fa:lock%</span> <div slot="text"> @@ -31,7 +31,7 @@ </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/> + <input name="agree-tou" type="checkbox" required/> <p><a :href="touUrl" target="_blank">利用規約</a>に同意する</p> </label> <ui-button type="submit">%i18n:@create%</ui-button> diff --git a/src/client/app/common/views/components/ui/button.vue b/src/client/app/common/views/components/ui/button.vue index 7723c83f57..e778750354 100644 --- a/src/client/app/common/views/components/ui/button.vue +++ b/src/client/app/common/views/components/ui/button.vue @@ -1,6 +1,6 @@ <template> -<div class="ui-button"> - <button :type="type"> +<div class="ui-button" :class="[styl]"> + <button :type="type" @click="$emit('click')"> <slot></slot> </button> </div> @@ -20,7 +20,9 @@ export default Vue.extend({ styl: 'fill' }; }, - inject: ['isCardChild'], + inject: { + isCardChild: { default: false } + }, created() { if (this.isCardChild) { this.styl = 'line'; diff --git a/src/client/app/common/views/components/ui/card.vue b/src/client/app/common/views/components/ui/card.vue index e2b15240e4..05c51bca6b 100644 --- a/src/client/app/common/views/components/ui/card.vue +++ b/src/client/app/common/views/components/ui/card.vue @@ -25,9 +25,13 @@ export default Vue.extend({ root(isDark) margin 16px padding 16px + color isDark ? #fff : #000 background isDark ? #282C37 : #fff box-shadow 0 3px 1px -2px rgba(#000, 0.2), 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12) + @media (min-width 500px) + padding 32px + > header font-weight normal font-size 24px diff --git a/src/client/app/common/views/components/ui/form.vue b/src/client/app/common/views/components/ui/form.vue index b6b4a76d2a..fc8fdad9c4 100644 --- a/src/client/app/common/views/components/ui/form.vue +++ b/src/client/app/common/views/components/ui/form.vue @@ -11,7 +11,7 @@ import Vue from 'vue'; export default Vue.extend({ props: { disabled: { - type: String, + type: Boolean, required: false } } diff --git a/src/client/app/common/views/components/ui/input.vue b/src/client/app/common/views/components/ui/input.vue index 167dd4e2a9..ec91ca364c 100644 --- a/src/client/app/common/views/components/ui/input.vue +++ b/src/client/app/common/views/components/ui/input.vue @@ -1,7 +1,7 @@ <template> <div class="ui-input" :class="[{ focused, filled }, styl]"> <div class="icon" ref="icon"><slot name="icon"></slot></div> - <div class="input" @click="focus"> + <div class="input" @click="focus" @mousedown="focus"> <div class="password-meter" v-if="withPasswordMeter" v-show="passwordStrength != ''" :data-strength="passwordStrength"> <div class="value" ref="passwordMetar"></div> </div> @@ -62,7 +62,6 @@ export default Vue.extend({ required: false }, autocomplete: { - type: String, required: false }, withPasswordMeter: { @@ -113,7 +112,9 @@ export default Vue.extend({ } } }, - inject: ['isCardChild'], + inject: { + isCardChild: { default: false } + }, created() { if (this.isCardChild) { this.styl = 'line'; @@ -160,6 +161,7 @@ root(isDark, fill) > .input display flex + cursor text if fill padding 6px 12px diff --git a/src/client/app/common/views/components/ui/radio.vue b/src/client/app/common/views/components/ui/radio.vue index 2b7f1d9dd4..04a46c5a96 100644 --- a/src/client/app/common/views/components/ui/radio.vue +++ b/src/client/app/common/views/components/ui/radio.vue @@ -87,7 +87,7 @@ root(isDark) width 20px height 20px background none - border solid 2px rgba(#000, 0.54) + border solid 2px isDark ? rgba(#fff, 0.7) : rgba(#000, 0.54) border-radius 100% transition inherit diff --git a/src/client/app/common/views/components/ui/select.vue b/src/client/app/common/views/components/ui/select.vue index 4577a15f68..4273a4a0de 100644 --- a/src/client/app/common/views/components/ui/select.vue +++ b/src/client/app/common/views/components/ui/select.vue @@ -48,7 +48,9 @@ export default Vue.extend({ this.v = v; } }, - inject: ['isCardChild'], + inject: { + isCardChild: { default: false } + }, created() { if (this.isCardChild) { this.styl = 'line'; @@ -101,7 +103,7 @@ root(isDark, fill) left 0 right 0 height 1px - background rgba(#000, 0.42) + background isDark ? rgba(#fff, 0.7) : rgba(#000, 0.42) &:after content '' @@ -141,14 +143,15 @@ root(isDark, fill) font-weight fill ? bold : normal font-size 16px height 32px + color isDark ? #fff : #000 background transparent border none border-radius 0 outline none box-shadow none - &[type='file'] - display none + * + color #000 > .prefix > .suffix diff --git a/src/client/app/common/views/components/ui/switch.vue b/src/client/app/common/views/components/ui/switch.vue index 24611b9aa0..a9e00d73d2 100644 --- a/src/client/app/common/views/components/ui/switch.vue +++ b/src/client/app/common/views/components/ui/switch.vue @@ -92,7 +92,7 @@ root(isDark) margin 3px 0 0 0 width 34px height 14px - background isDark ? rgba(#fff, 0.1) : rgba(#000, 0.25) + background isDark ? rgba(#fff, 0.15) : rgba(#000, 0.25) outline none border-radius 14px transition inherit diff --git a/src/client/app/config.ts b/src/client/app/config.ts index 70c085de1c..e4a7ff6d38 100644 --- a/src/client/app/config.ts +++ b/src/client/app/config.ts @@ -1,6 +1,8 @@ declare const _HOST_: string; declare const _HOSTNAME_: string; declare const _URL_: string; +declare const _NAME_: string; +declare const _DESCRIPTION_: string; declare const _API_URL_: string; declare const _WS_URL_: string; declare const _DOCS_URL_: string; @@ -21,6 +23,8 @@ declare const _GOOGLE_MAPS_API_KEY_: string; export const host = _HOST_; export const hostname = _HOSTNAME_; export const url = _URL_; +export const name = _NAME_; +export const description = _DESCRIPTION_; export const apiUrl = _API_URL_; export const wsUrl = _WS_URL_; export const docsUrl = _DOCS_URL_; diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue index beac788482..2a32e982ba 100644 --- a/src/client/app/mobile/views/pages/settings.vue +++ b/src/client/app/mobile/views/pages/settings.vue @@ -1,41 +1,27 @@ <template> <mk-ui> <span slot="header">%fa:cog%%i18n:@settings%</span> - <main> - <p v-html="'%i18n:@signed-in-as%'.replace('{}', '<b>' + name + '</b>')"></p> + <main :data-darkmode="$store.state.device.darkmode"> + <div class="signin-as" v-html="'%i18n:@signed-in-as%'.replace('{}', '<b>' + name + '</b>')"></div> + <div> <x-profile/> <ui-card> <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> + <ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch> + <ui-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</ui-switch> <div> <div class="md-body-2">%i18n:@timeline%</div> - - <div> - <ui-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget">%i18n:@show-reply-target%</ui-switch> - </div> - - <div> - <ui-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes">%i18n:@show-my-renotes%</ui-switch> - </div> - - <div> - <ui-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes">%i18n:@show-renoted-my-notes%</ui-switch> - </div> + <ui-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget">%i18n:@show-reply-target%</ui-switch> + <ui-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes">%i18n:@show-my-renotes%</ui-switch> + <ui-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes">%i18n:@show-renoted-my-notes%</ui-switch> </div> <div> <div class="md-body-2">%i18n:@post-style%</div> - <ui-radio v-model="postStyle" value="standard">%i18n:@post-style-standard%</ui-radio> <ui-radio v-model="postStyle" value="smart">%i18n:@post-style-smart%</ui-radio> </div> @@ -43,26 +29,11 @@ <ui-card> <div slot="title">%fa:cog% %i18n:@behavior%</div> - - <div> - <ui-switch v-model="$store.state.settings.fetchOnScroll" @change="onChangeFetchOnScroll">%i18n:@fetch-on-scroll%</ui-switch> - </div> - - <div> - <ui-switch v-model="$store.state.settings.disableViaMobile" @change="onChangeDisableViaMobile">%i18n:@disable-via-mobile%</ui-switch> - </div> - - <div> - <ui-switch v-model="loadRawImages">%i18n:@load-raw-images%</ui-switch> - </div> - - <div> - <ui-switch v-model="$store.state.settings.loadRemoteMedia" @change="onChangeLoadRemoteMedia">%i18n:@load-remote-media%</ui-switch> - </div> - - <div> - <ui-switch v-model="lightmode">%i18n:@i-am-under-limited-internet%</ui-switch> - </div> + <ui-switch v-model="$store.state.settings.fetchOnScroll" @change="onChangeFetchOnScroll">%i18n:@fetch-on-scroll%</ui-switch> + <ui-switch v-model="$store.state.settings.disableViaMobile" @change="onChangeDisableViaMobile">%i18n:@disable-via-mobile%</ui-switch> + <ui-switch v-model="loadRawImages">%i18n:@load-raw-images%</ui-switch> + <ui-switch v-model="$store.state.settings.loadRemoteMedia" @change="onChangeLoadRemoteMedia">%i18n:@load-remote-media%</ui-switch> + <ui-switch v-model="lightmode">%i18n:@i-am-under-limited-internet%</ui-switch> </ui-card> <ui-card> @@ -98,13 +69,16 @@ <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"> + <ui-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-button> </ui-card> </div> - <p><small>ver {{ version }} ({{ codename }})</small></p> + + <footer> + <small>ver {{ version }} ({{ codename }})</small> + </footer> </main> </mk-ui> </template> @@ -249,13 +223,18 @@ root(isDark) max-width 500px width 100% - > p - display block - margin 16px 0 + > .signin-as + margin 16px padding 16px text-align center - color isDark ? #cad2da : #2c662d - background #fcfff5 + color isDark ? #49ab63 : #2c662d + background isDark ? #273c34 : #fcfff5 + box-shadow 0 3px 1px -2px rgba(#000, 0.2), 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12) + + > footer + margin 16px + text-align center + color isDark ? #c9d2e0 : #888 main[data-darkmode] root(true) 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 64adac01e6..da97cbebd7 100644 --- a/src/client/app/mobile/views/pages/settings/settings.profile.vue +++ b/src/client/app/mobile/views/pages/settings/settings.profile.vue @@ -30,11 +30,13 @@ <ui-input type="file" @change="onAvatarChange"> <span>%i18n:@avatar%</span> <span slot="icon">%fa:image%</span> + <span slot="text" v-if="avatarUploading">%i18n:@uploading%<mk-ellipsis/></span> </ui-input> <ui-input type="file" @change="onBannerChange"> <span>%i18n:@banner%</span> <span slot="icon">%fa:image%</span> + <span slot="text" v-if="bannerUploading">%i18n:@uploading%<mk-ellipsis/></span> </ui-input> <ui-switch v-model="isCat">%i18n:@is-cat%</ui-switch> @@ -62,7 +64,8 @@ export default Vue.extend({ isBot: false, isCat: false, saving: false, - uploading: false + avatarUploading: false, + bannerUploading: false }; }, @@ -80,7 +83,7 @@ export default Vue.extend({ methods: { onAvatarChange([file]) { - this.uploading = true; + this.avatarUploading = true; const data = new FormData(); data.append('file', file); @@ -93,16 +96,16 @@ export default Vue.extend({ .then(response => response.json()) .then(f => { this.avatarId = f.id; - this.uploading = false; + this.avatarUploading = false; }) .catch(e => { - this.uploading = false; + this.avatarUploading = false; alert('%18n:!@upload-failed%'); }); }, onBannerChange([file]) { - this.uploading = true; + this.bannerUploading = true; const data = new FormData(); data.append('file', file); @@ -115,10 +118,10 @@ export default Vue.extend({ .then(response => response.json()) .then(f => { this.bannerId = f.id; - this.uploading = false; + this.bannerUploading = false; }) .catch(e => { - this.uploading = false; + this.bannerUploading = false; alert('%18n:!@upload-failed%'); }); }, diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue index 3b37a185bd..3bf2a0af9f 100644 --- a/src/client/app/mobile/views/pages/welcome.vue +++ b/src/client/app/mobile/views/pages/welcome.vue @@ -35,7 +35,7 @@ <script lang="ts"> import Vue from 'vue'; -import { apiUrl, copyright, host } from '../../../config'; +import { apiUrl, copyright, host, name, description } from '../../../config'; export default Vue.extend({ data() { @@ -48,7 +48,9 @@ export default Vue.extend({ apiUrl, copyright, users: [], - host + host, + name, + description }; }, mounted() { diff --git a/src/config/types.ts b/src/config/types.ts index 910c03c2c1..d557f2afde 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -15,6 +15,8 @@ export type Source = { */ url: string; }; + name?: string; + description?: string; url: string; port: number; https?: { [x: string]: string }; diff --git a/webpack.config.ts b/webpack.config.ts index 67fb929449..8376cd9c40 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -79,6 +79,8 @@ const consts = { _DEV_URL_: config.dev_url, _LANG_: '%lang%', _LANGS_: Object.keys(locales).map(l => [l, locales[l].meta.lang]), + _NAME_: config.name, + _DESCRIPTION_: config.description, _HOST_: config.host, _HOSTNAME_: config.hostname, _URL_: config.url, From bddff17e5e22104a799d0147301570239a895fbc Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Fri, 15 Jun 2018 07:58:27 +0900 Subject: [PATCH 11/11] wip --- src/client/app/mobile/views/pages/settings.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue index 2a32e982ba..1c5a43ede4 100644 --- a/src/client/app/mobile/views/pages/settings.vue +++ b/src/client/app/mobile/views/pages/settings.vue @@ -14,14 +14,14 @@ <ui-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</ui-switch> <div> - <div class="md-body-2">%i18n:@timeline%</div> + <div>%i18n:@timeline%</div> <ui-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget">%i18n:@show-reply-target%</ui-switch> <ui-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes">%i18n:@show-my-renotes%</ui-switch> <ui-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes">%i18n:@show-renoted-my-notes%</ui-switch> </div> <div> - <div class="md-body-2">%i18n:@post-style%</div> + <div>%i18n:@post-style%</div> <ui-radio v-model="postStyle" value="standard">%i18n:@post-style-standard%</ui-radio> <ui-radio v-model="postStyle" value="smart">%i18n:@post-style-smart%</ui-radio> </div> @@ -48,7 +48,7 @@ <option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option> </optgroup> </ui-select> - <span class="md-helper-text">%fa:info-circle% %i18n:@lang-tip%</span> + <span>%fa:info-circle% %i18n:@lang-tip%</span> </ui-card> <ui-card> @@ -69,7 +69,7 @@ <template v-if="latestVersion !== undefined"> <div>%i18n:@latest-version% <i>{{ latestVersion ? latestVersion : version }}</i></div> </template> - <ui-button class="md-raised md-primary" @click="checkForUpdate" :disabled="checkingForUpdate"> + <ui-button @click="checkForUpdate" :disabled="checkingForUpdate"> <template v-if="checkingForUpdate">%i18n:@update-checking%<mk-ellipsis/></template> <template v-else>%i18n:@check-for-updates%</template> </ui-button>