Bladeren bron

Refactor error ui for a cleaner look, which also works better on mobile

sbkwgh 7 jaren geleden
bovenliggende
commit
351dd314c9

+ 10 - 42
frontend/src/components/ErrorTooltip.vue

@@ -1,7 +1,7 @@
 <template>
 	<div
 		class='error_tooltip'
-		:class='{"error_tooltip--show": error, "error_tooltip--bottom": bottom }'
+		:class='{"error_tooltip--show": error }'
 	>
 		{{delayed_error}}
 	</div>
@@ -10,7 +10,7 @@
 <script>
 	export default {
 		name: 'ErrorTooltip',
-		props: ['error', 'bottom'],
+		props: ['error'],
 		data () {
 			return {
 				delayed_error: this.error
@@ -34,52 +34,20 @@
 	@import '../assets/scss/variables.scss';
 
 	.error_tooltip {
-		position: absolute;
-		background-color: #ffeff1;
-		border: 0.125rem solid #D32F2F;
-		font-size: 0.9rem;
-		padding: 0.1rem 0.25rem;
-		top: 0.2125rem;
-		border-radius: 0.2rem;
-		left: calc(100% + 0.25rem);
-		white-space: nowrap;
+		font-size: .85rem;
 		opacity: 0;
-		pointer-events: none;
-		margin-top: -1rem;
-		transition: opacity 0.2s, margin-top 0.2s;
+		max-height: 0px;
+		overflow: hidden;
+		color: $color__red--primary;
+		padding: 0;
+		transition: all 0.2s cubic-bezier(0.23, 1, 0.32, 1);
 
 		&:first-letter{ text-transform: capitalize; }
 
-		&::after {
-			content: '';
-			position: relative;
-			width: 0;
-			height: 0;
-			display: inline-block;
-			right: calc(100% + 0.3rem);
-			border-top: 0.3rem solid transparent;
-			border-bottom: 0.3rem solid transparent;
-			border-right: 0.3rem solid #D32F2F;
-		}
-
 		@at-root #{&}--show {
+			max-height: 2rem;
+			padding-top: 0.125rem;
 			opacity: 1;
-			pointer-events: all;
-			margin-top: 0;
-			transition: opacity 0.2s, margin-top 0.2s;
-		}
-
-		@at-root #{&}--bottom {
-			left: 0;
-			top: calc(100% + 0.25rem);
-
-			&::after {
-				top: -1.1rem;
-				right: calc(100% - 0.5rem);
-				border-left: 0.3rem solid transparent;
-				border-right: 0.3rem solid transparent;
-				border-bottom: 0.3rem solid #D32F2F;
-			}
 		}
 	}
 </style>

+ 11 - 3
frontend/src/components/FancyInput.vue

@@ -4,7 +4,6 @@
 			 style='position: relative; display: inline-block;'
 			 v-bind:style='{width: width || "10rem"}'
 		>
-			<error-tooltip :error='error' :bottom='errorBottom'></error-tooltip>
 			<div
 				class='fancy_input__placeholder'
 				:class='{
@@ -17,7 +16,10 @@
 			<input
 				v-bind:type='type || "text"'
 				class='input'
-				:class='{"fancy_input__input--large": large}'
+				:class='{
+					"fancy_input__input--large": large,
+					"fancy_input__input--error": error
+				}'
 				v-bind:value='value'
 				v-bind:style='{width: width || "10rem"}'
 				v-on:input='updateValue($event.target.value)'
@@ -25,6 +27,7 @@
 				@blur='removeActive'
 			>
 		</div>
+		<error-tooltip :error='error'></error-tooltip>
 	</div>
 </template>
 
@@ -33,7 +36,7 @@
 
 	export default {
 		name: 'FancyInput',
-		props: ['value', 'placeholder', 'width', 'type', 'error', 'large', 'error-bottom'],
+		props: ['value', 'placeholder', 'width', 'type', 'error', 'large'],
 		components: {
 			ErrorTooltip
 		},
@@ -65,9 +68,14 @@
 		margin-bottom: 0.5rem;
 
 		@at-root #{&}__input {
+			transition: border-color 0.2s;
+
 			@at-root #{&}--large {
 				padding: 0.5rem;
 			}
+			@at-root #{&}--error {
+				border-color: $color__red--primary;
+			}
 		}
 
 		@at-root #{&}__placeholder {

+ 1 - 1
frontend/src/components/FancyTextarea.vue

@@ -4,7 +4,6 @@
 		 style='position: relative; display: inline-block;'
 		 v-bind:style='{width: width || "20rem"}'
 		>
-			<error-tooltip :error='error'></error-tooltip>
 			<div
 				class='fancy_textarea__placeholder'
 				:class='{"fancy_textarea__placeholder--active": active || value.length}'
@@ -21,6 +20,7 @@
 			>
 			</textarea>
 		</div>
+		<error-tooltip :error='error'></error-tooltip>
 	</div>
 </template>
 

+ 0 - 1
frontend/src/components/InputEditorCore.vue

@@ -2,7 +2,6 @@
 	<div
 		class='input_editor_core'
 	>
-		<error-tooltip :error='error'></error-tooltip>
 		<div>
 			<emoji-selector
 				v-model='emojiSelectorVisible'

+ 60 - 20
frontend/src/components/routes/ThreadNew.vue

@@ -4,21 +4,25 @@
 		<div class='h1'>Post new thread</div>
 		<div class='thread_meta_info'>
 			<div class='thread_meta_info__text'>Enter the thread title and the category to post it in</div>
-			<select-button v-model='selectedCategory' :options='categories'></select-button>
-			<fancy-input
-				placeholder='Thread title'
-				v-model='name'
-				:error='errors.name'
-				class='thread_meta_info__title'
-				large='true'
-				width='15rem'
-			></fancy-input>
-			
-			<button
-				class='thread_meta_info__add_poll button button--thin_text'
-				v-if='!showPoll'
-				@click='togglePoll(true)'
-			>Add poll</button>
+
+			<div class='thread_meta_info__form'>
+				<select-button v-model='selectedCategory' :options='categories'></select-button>
+				<fancy-input
+					placeholder='Thread title'
+					v-model='name'
+					:error='errors.name'
+					class='thread_meta_info__title'
+					large='true'
+					width='15rem'
+				></fancy-input>
+				
+				<button
+					class='thread_meta_info__add_poll button button--thin_text'
+					v-if='!showPoll'
+					@click='togglePoll(true)'
+				>Add poll</button>
+			</div>
+
 			<transition name='slide'>
 				<div class='thread_meta_info__poll' v-if='showPoll'>
 					<div class='thread_meta_info__poll__top_bar'>
@@ -44,7 +48,7 @@
 							></fancy-input>
 							<span @click='removePollAnswer($index)' title='Remove answer'>&times;</span>
 						</div>
-						<div>
+						<div class='thread_meta_info__form'>
 							<fancy-input
 								v-model='newPollAnswer'
 								placeholder='Option/answer for poll'
@@ -59,14 +63,20 @@
 				</div>
 			</transition>
 		</div>
-		<div class='editor' :class='{"editor--focus": focusInput}'>
+
+		<div
+			class='editor'
+			:class='{
+				"editor--focus": focusInput,
+				"editor--error": errors.content
+			}'
+		>
 			<div class='editor__input'>
 				<div class='editor__format_bar editor__format_bar--editor'>
 					editor
 				</div>
 				<input-editor-core
 					v-model='editor'
-					:error='errors.content'
 					@mentions='setMentions'
 					@focus='setFocusInput(true)'
 					@blur='setFocusInput(false)'
@@ -79,6 +89,8 @@
 				<input-editor-preview :value='editor' :mentions='mentions'></input-editor-preview>
 			</div>
 		</div>
+		<error-tooltip :error='errors.content' class='editor_error'></error-tooltip>
+
 		<loading-button class='button--green submit' :loading='loading' @click='postThread'>Post thread</loading-button>
 	</div>
 </template>
@@ -89,6 +101,7 @@
 	import FancyInput from '../FancyInput'
 	import SelectButton from '../SelectButton'
 	import LoadingButton from '../LoadingButton'
+	import ErrorTooltip from '../ErrorTooltip'
 
 	import AjaxErrorHandler from '../../assets/js/errorHandler'
 	import logger from '../../assets/js/logger'
@@ -100,7 +113,8 @@
 			InputEditorPreview,
 			SelectButton,
 			FancyInput,
-			LoadingButton
+			LoadingButton,
+			ErrorTooltip
 		},
 		data () {
 			return {
@@ -179,7 +193,7 @@
 				this.clearErrors()
 
 				if(!this.editor.trim().length) {
-					errors.push({name: 'content', error: 'Cannot be blank'})
+					errors.push({name: 'content', error: 'Post content cannot be blank'})
 				} if(!this.name.trim().length) {
 					errors.push({name: 'name', error: 'Cannot be blank'})
 				} if(this.showPoll && !this.pollQuestion.trim().length) {
@@ -287,6 +301,11 @@
 			display: inline-block;
 		}
 
+		@at-root #{&}__form {
+			display: flex;
+			align-items: baseline;
+		}
+
 		@at-root #{&}__add_poll {
 			margin-top: 0.5rem;
 		}
@@ -339,12 +358,16 @@
 		background-color: #fff;
 		border-radius: 0.25rem;
 		border: thin solid $color__gray--darker;
+		overflow: hidden;
 
 		transition: all 0.2s;
 
 		@at-root #{&}--focus {
 			border: thin solid $color__gray--darkest;
 		}
+		@at-root #{&}--error {
+			border: thin solid $color__red--primary;
+		}
 
 		@at-root #{&}__format_bar {
 			height: 2.5rem;
@@ -387,8 +410,25 @@
 		}
 	}
 
+	.editor_error {
+		width: 100%;
+		background: #fff;
+		margin-top: 0.5rem;
+		border-radius: 0.2rem;
+		border: thin solid $color__red--primary;
+		
+		&.error_tooltip--show {
+			max-height: 4rem;
+			padding: 0.5rem;
+		}
+	}
+
 	@media (max-width: 420px) {
 		.thread_meta_info {
+			@at-root #{&}__form {
+				flex-direction: column;
+			}
+
 			@at-root #{&}__title.fancy_input {
 				margin: 0;
 				margin-top: 0.5rem;