wip
This commit is contained in:
		
							parent
							
								
									120c11b181
								
							
						
					
					
						commit
						c5e9b69eb3
					
				|  | @ -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…
	
		Reference in New Issue