wip
This commit is contained in:
		
							parent
							
								
									120c11b181
								
							
						
					
					
						commit
						c5e9b69eb3
					
				
					 5 changed files with 188 additions and 34 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -143,7 +143,6 @@ root(isDark)
 | 
			
		|||
		> span
 | 
			
		||||
			display block
 | 
			
		||||
			line-height 20px
 | 
			
		||||
			font-weight bold
 | 
			
		||||
			color isDark ? #c4ccd2 : rgba(#000, 0.75)
 | 
			
		||||
			transition inherit
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue