diff --git a/src/client/app/common/views/components/ui/card.vue b/src/client/app/common/views/components/ui/card.vue index 5ba15dad7..97f06ca65 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 7461aac7f..3a474f024 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 e78951a35..f86030986 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 0a9f60f1b..d5e2b1562 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 de891b573..64adac01e 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>