Просмотр исходного кода

feat: AdvancedTable footer for pagination control

Owen Diffey 3 лет назад
Родитель
Сommit
37a8911b76
1 измененных файлов с 258 добавлено и 223 удалено
  1. 258 223
      frontend/src/components/AdvancedTable.vue

+ 258 - 223
frontend/src/components/AdvancedTable.vue

@@ -18,181 +18,194 @@
 				}}
 			</button>
 		</div>
-		<div class="table-container">
-			<table class="table">
-				<thead>
-					<draggable
-						item-key="name"
-						v-model="orderedColumns"
-						v-bind="columnDragOptions"
-						tag="tr"
-						draggable=".item-draggable"
-					>
-						<template #item="{ element: column }">
-							<th
-								:class="{
-									sortable: column.sortable,
-									'item-draggable': column.name !== 'select'
-								}"
-								v-if="
-									enabledColumns.indexOf(column.name) !== -1
-								"
-							>
-								<span @click="changeSort(column)">
-									{{ column.displayName }}
-									<span
-										v-if="
-											column.sortable &&
-											sort[column.sortProperty]
-										"
-										>({{ sort[column.sortProperty] }})</span
-									>
-								</span>
-								<tippy
-									v-if="column.sortable"
-									:touch="true"
-									:interactive="true"
-									placement="bottom"
-									theme="search"
-									ref="search"
-									trigger="click"
+		<div class="table-outer-container">
+			<div class="table-container">
+				<table class="table">
+					<thead>
+						<draggable
+							item-key="name"
+							v-model="orderedColumns"
+							v-bind="columnDragOptions"
+							tag="tr"
+							draggable=".item-draggable"
+						>
+							<template #item="{ element: column }">
+								<th
+									:class="{
+										sortable: column.sortable,
+										'item-draggable':
+											column.name !== 'select'
+									}"
+									v-if="
+										enabledColumns.indexOf(column.name) !==
+										-1
+									"
 								>
-									<i
-										class="
-											material-icons
-											action-dropdown-icon
-										"
-										:content="`Filter by ${column.displayName}`"
-										v-tippy
-										@click.prevent="true"
-										>search</i
+									<span @click="changeSort(column)">
+										{{ column.displayName }}
+										<span
+											v-if="
+												column.sortable &&
+												sort[column.sortProperty]
+											"
+											>({{
+												sort[column.sortProperty]
+											}})</span
+										>
+									</span>
+									<tippy
+										v-if="column.sortable"
+										:touch="true"
+										:interactive="true"
+										placement="bottom"
+										theme="search"
+										ref="search"
+										trigger="click"
 									>
-
-									<template #content>
-										<div
+										<i
 											class="
-												control
-												is-grouped
-												input-with-button
+												material-icons
+												action-dropdown-icon
 											"
+											:content="`Filter by ${column.displayName}`"
+											v-tippy
+											@click.prevent="true"
+											>search</i
 										>
-											<p class="control is-expanded">
-												<input
-													class="input"
-													type="text"
-													:placeholder="`Filter by ${column.displayName}`"
-													:value="
-														column.filterProperty !==
-														null
-															? filter[
-																	column
-																		.filterProperty
-															  ]
-															: ''
-													"
-													@keyup.enter="
-														changeFilter(
-															column,
-															$event
-														)
-													"
-												/>
-											</p>
-											<p class="control">
-												<a class="button is-info">
-													<i
-														class="
-															material-icons
-															icon-with-button
+
+										<template #content>
+											<div
+												class="
+													control
+													is-grouped
+													input-with-button
+												"
+											>
+												<p class="control is-expanded">
+													<input
+														class="input"
+														type="text"
+														:placeholder="`Filter by ${column.displayName}`"
+														:value="
+															column.filterProperty !==
+															null
+																? filter[
+																		column
+																			.filterProperty
+																  ]
+																: ''
 														"
-														>search</i
-													>
-												</a>
-											</p>
-										</div>
-									</template>
-								</tippy>
-							</th>
-						</template>
-					</draggable>
-				</thead>
-				<tbody>
-					<tr
-						v-for="(item, itemIndex) in data"
-						:key="item._id"
-						:class="{
-							selected: item.selected,
-							highlighted: item.highlighted
-						}"
-						@click="clickItem(itemIndex, $event)"
-					>
-						<td
-							v-for="column in sortedFilteredColumns"
-							:key="`${item._id}-${column.name}`"
+														@keyup.enter="
+															changeFilter(
+																column,
+																$event
+															)
+														"
+													/>
+												</p>
+												<p class="control">
+													<a class="button is-info">
+														<i
+															class="
+																material-icons
+																icon-with-button
+															"
+															>search</i
+														>
+													</a>
+												</p>
+											</div>
+										</template>
+									</tippy>
+								</th>
+							</template>
+						</draggable>
+					</thead>
+					<tbody>
+						<tr
+							v-for="(item, itemIndex) in data"
+							:key="item._id"
+							:class="{
+								selected: item.selected,
+								highlighted: item.highlighted
+							}"
+							@click="clickItem(itemIndex, $event)"
 						>
-							<slot
-								:name="`column-${column.name}`"
-								:item="item"
-							></slot>
-						</td>
-					</tr>
-				</tbody>
-			</table>
-		</div>
-		<div class="row control">
-			<label class="label">Items per page</label>
-			<p class="control select">
-				<select v-model.number="pageSize" @change="getData()">
-					<option value="10">10</option>
-					<option value="25">25</option>
-					<option value="50">50</option>
-					<option value="100">100</option>
-					<option value="250">250</option>
-					<option value="500">500</option>
-					<option value="1000">1000</option>
-				</select>
-			</p>
-		</div>
-		<div class="row">
-			<button
-				v-if="page > 1"
-				class="button is-primary material-icons"
-				@click="changePage(1)"
-				content="First Page"
-				v-tippy
-			>
-				skip_previous
-			</button>
-			<button
-				v-if="page > 1"
-				class="button is-primary material-icons"
-				@click="changePage(page - 1)"
-				content="Previous Page"
-				v-tippy
-			>
-				fast_rewind
-			</button>
+							<td
+								v-for="column in sortedFilteredColumns"
+								:key="`${item._id}-${column.name}`"
+							>
+								<slot
+									:name="`column-${column.name}`"
+									:item="item"
+								></slot>
+							</td>
+						</tr>
+					</tbody>
+				</table>
+			</div>
+			<div class="table-footer">
+				<div>
+					<button
+						v-if="page > 1"
+						class="button is-primary material-icons"
+						@click="changePage(1)"
+						content="First Page"
+						v-tippy
+					>
+						skip_previous
+					</button>
+					<button
+						v-if="page > 1"
+						class="button is-primary material-icons"
+						@click="changePage(page - 1)"
+						content="Previous Page"
+						v-tippy
+					>
+						fast_rewind
+					</button>
 
-			<p>Page {{ page }} / {{ lastPage }}</p>
+					<p>Page {{ page }} / {{ lastPage }}</p>
 
-			<button
-				v-if="page < lastPage"
-				class="button is-primary material-icons"
-				@click="changePage(page + 1)"
-				content="Next Page"
-				v-tippy
-			>
-				fast_forward
-			</button>
-			<button
-				v-if="page < lastPage"
-				class="button is-primary material-icons"
-				@click="changePage(lastPage)"
-				content="Last Page"
-				v-tippy
-			>
-				skip_next
-			</button>
+					<button
+						v-if="page < lastPage"
+						class="button is-primary material-icons"
+						@click="changePage(page + 1)"
+						content="Next Page"
+						v-tippy
+					>
+						fast_forward
+					</button>
+					<button
+						v-if="page < lastPage"
+						class="button is-primary material-icons"
+						@click="changePage(lastPage)"
+						content="Last Page"
+						v-tippy
+					>
+						skip_next
+					</button>
+				</div>
+				<div>
+					<div class="control">
+						<label class="label">Items per page</label>
+						<p class="control select">
+							<select
+								v-model.number="pageSize"
+								@change="getData()"
+							>
+								<option value="10">10</option>
+								<option value="25">25</option>
+								<option value="50">50</option>
+								<option value="100">100</option>
+								<option value="250">250</option>
+								<option value="500">500</option>
+								<option value="1000">1000</option>
+							</select>
+						</p>
+					</div>
+				</div>
+			</div>
 		</div>
 	</div>
 </template>
@@ -393,8 +406,8 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-.night-mode {
-	.table {
+.night-mode .table-outer-container {
+	.table-container .table {
 		&,
 		thead th {
 			background-color: var(--dark-grey-3);
@@ -413,87 +426,109 @@ export default {
 			}
 		}
 	}
+
+	.table-footer {
+		background-color: var(--dark-grey-3);
+		color: var(--light-grey-2);
+	}
 }
 
-.table-container {
+.table-outer-container {
 	border-radius: 5px;
 	box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
-	overflow-x: auto;
 	margin: 10px 0;
+	overflow: hidden;
 
-	table {
-		border-collapse: separate;
+	.table-container {
+		overflow-x: auto;
 
-		thead {
-			tr {
-				th {
-					&.sortable {
-						cursor: pointer;
-					}
+		table {
+			border-collapse: separate;
 
-					span > .material-icons {
-						font-size: 22px;
-						position: relative;
-						top: 6px;
+			thead {
+				tr {
+					th {
+						white-space: nowrap;
 
-						&:first-child {
-							margin-left: auto;
+						&.sortable {
+							cursor: pointer;
+						}
+
+						span > .material-icons {
+							font-size: 22px;
+							position: relative;
+							top: 6px;
+
+							&:first-child {
+								margin-left: auto;
+							}
 						}
 					}
 				}
 			}
-		}
 
-		tbody {
-			tr {
-				&.selected td:first-child {
-					border-left: 5px solid var(--primary-color);
-					padding-left: 0;
-				}
+			tbody {
+				tr {
+					&.selected td:first-child {
+						border-left: 5px solid var(--primary-color);
+						padding-left: 0;
+					}
 
-				&.highlighted {
-					background-color: var(--light-grey);
+					&.highlighted {
+						background-color: var(--light-grey);
 
-					td:first-child {
-						border-left: 5px solid var(--red);
-						padding-left: 0;
+						td:first-child {
+							border-left: 5px solid var(--red);
+							padding-left: 0;
+						}
 					}
-				}
 
-				&.selected.highlighted td:first-child {
-					border-left: 5px solid var(--green);
-					padding-left: 0;
+					&.selected.highlighted td:first-child {
+						border-left: 5px solid var(--green);
+						padding-left: 0;
+					}
 				}
 			}
 		}
-	}
 
-	table thead tr th:first-child,
-	table tbody tr td:first-child {
-		position: sticky;
-		left: 0;
-		z-index: 2;
-		padding: 0;
-		padding-left: 5px;
+		table thead tr th:first-child,
+		table tbody tr td:first-child {
+			position: sticky;
+			left: 0;
+			z-index: 2;
+			padding: 0;
+			padding-left: 5px;
+		}
 	}
-}
 
-.row {
-	display: flex;
-	flex-direction: row;
-	flex-wrap: wrap;
-	justify-content: center;
-	margin: 10px;
+	.table-footer {
+		display: flex;
+		flex-direction: row;
+		flex-wrap: wrap;
+		justify-content: space-between;
+		line-height: 36px;
+		background-color: var(--white);
 
-	button {
-		font-size: 22px;
-		margin: auto 5px;
-	}
+		& > div:first-child,
+		div .control {
+			display: flex;
+			flex-direction: row;
+			margin-bottom: 0 !important;
 
-	p,
-	label {
-		font-size: 18px;
-		margin: auto 5px;
+			button {
+				margin: 5px;
+				font-size: 20px;
+			}
+			p,
+			label {
+				margin: 5px;
+				font-size: 14px;
+				font-weight: 600;
+			}
+			&.select::after {
+				top: 18px;
+			}
+		}
 	}
 }
 </style>