diff options
| author | syuilo <syuilotan@yahoo.co.jp> | 2018-06-14 14:52:37 +0900 |
|---|---|---|
| committer | syuilo <syuilotan@yahoo.co.jp> | 2018-06-14 14:52:37 +0900 |
| commit | a1ae832129e8bfe8c082064349e2b9973be5f0e5 (patch) | |
| tree | e143eb1a039179794bd6f23b65bdbc88e549a317 /src/client/app/common/views/components/ui | |
| parent | wip (diff) | |
| download | misskey-a1ae832129e8bfe8c082064349e2b9973be5f0e5.tar.gz misskey-a1ae832129e8bfe8c082064349e2b9973be5f0e5.tar.bz2 misskey-a1ae832129e8bfe8c082064349e2b9973be5f0e5.zip | |
wip
Diffstat (limited to 'src/client/app/common/views/components/ui')
| -rw-r--r-- | src/client/app/common/views/components/ui/button.vue | 46 | ||||
| -rw-r--r-- | src/client/app/common/views/components/ui/form.vue | 28 | ||||
| -rw-r--r-- | src/client/app/common/views/components/ui/group.vue | 23 | ||||
| -rw-r--r-- | src/client/app/common/views/components/ui/input.vue | 215 | ||||
| -rw-r--r-- | src/client/app/common/views/components/ui/switch.vue | 199 | ||||
| -rw-r--r-- | src/client/app/common/views/components/ui/textarea.vue | 127 |
6 files changed, 638 insertions, 0 deletions
diff --git a/src/client/app/common/views/components/ui/button.vue b/src/client/app/common/views/components/ui/button.vue new file mode 100644 index 0000000000..57747fd469 --- /dev/null +++ b/src/client/app/common/views/components/ui/button.vue @@ -0,0 +1,46 @@ +<template> +<div class="ui-button"> + <button :type="type"> + <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% + 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%) + + &: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/ui/textarea.vue b/src/client/app/common/views/components/ui/textarea.vue new file mode 100644 index 0000000000..0a9f60f1bc --- /dev/null +++ b/src/client/app/common/views/components/ui/textarea.vue @@ -0,0 +1,127 @@ +<template> +<div class="ui-textarea" :class="{ focused, filled }"> + <div class="input"> + <span class="label" ref="label"><slot></slot></span> + <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"> + </textarea> + </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 + }, + required: { + type: Boolean, + required: false + }, + readonly: { + type: Boolean, + required: false + }, + pattern: { + type: String, + required: false + }, + autocomplete: { + type: String, + required: false + } + }, + data() { + return { + focused: false, + passwordStrength: '' + } + }, + computed: { + filled(): boolean { + return this.value != '' && this.value != null; + } + }, + methods: { + focus() { + this.$refs.input.focus(); + } + } +}); +</script> + +<style lang="stylus" scoped> +@import '~const.styl' + +.ui-textarea + margin 32px 0 + + > .input + padding 12px + background rgba(#000, 0.035) + border-radius 6px + + > .label + position absolute + top 6px + left 12px + 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) + + > textarea + display block + width 100% + min-height 100px + padding 0 + font inherit + font-weight bold + font-size 16px + background transparent + border none + border-radius 0 + outline none + box-shadow none + + > .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> |