Skip to content

Commit 11ebb5a

Browse files
authored
Merge branch 'main' into workspace-refactor-changes
2 parents 2bd9b88 + 971ae10 commit 11ebb5a

File tree

2 files changed

+95
-172
lines changed

2 files changed

+95
-172
lines changed

src/components/smart/Table.vue

Lines changed: 90 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,101 @@
11
<template>
2-
<div class="flex flex-1 flex-col">
3-
<div v-if="pagination" class="mb-3 flex items-center justify-end">
4-
<HoppButtonSecondary
5-
outline
6-
filled
7-
:icon="IconLeft"
8-
:disabled="page === 1"
9-
@click="changePage(PageDirection.Previous)"
10-
/>
11-
12-
<span class="flex h-full w-10 items-center justify-center">{{
13-
page
14-
}}</span>
15-
16-
<HoppButtonSecondary
17-
outline
18-
filled
19-
:icon="IconRight"
20-
:disabled="page === pagination.totalPages"
21-
@click="changePage(PageDirection.Next)"
22-
/>
23-
</div>
24-
25-
<div class="overflow-auto rounded-md border border-dividerDark shadow-md">
26-
<!-- An Extension Slot to extend the table functionality such as search -->
27-
<slot name="extension"></slot>
28-
29-
<table class="w-full table-fixed">
30-
<thead>
2+
<div class="overflow-auto rounded-md border border-dividerDark shadow-md">
3+
<!-- An Extension Slot to extend the table functionality such as search -->
4+
<slot name="extension"></slot>
5+
6+
<table class="w-full table-fixed">
7+
<thead>
8+
<tr
9+
class="border-b border-dividerDark bg-primaryLight text-left text-sm text-secondary"
10+
>
11+
<th v-if="selectedRows" class="w-24">
12+
<input
13+
ref="selectAllCheckbox"
14+
type="checkbox"
15+
:checked="areAllRowsSelected"
16+
:disabled="loading"
17+
class="flex h-full w-full items-center justify-center"
18+
@click.stop="toggleAllRows"
19+
/>
20+
</th>
21+
<slot name="head">
22+
<th
23+
v-for="th in headings"
24+
:key="th.key"
25+
scope="col"
26+
class="px-6 py-3"
27+
>
28+
{{ th.label ?? th.key }}
29+
</th>
30+
</slot>
31+
</tr>
32+
</thead>
33+
34+
<tbody class="divide-y divide-divider">
35+
<tr v-if="loading">
36+
<slot name="loading-state">
37+
<td :colspan="columnSpan">
38+
<div class="mx-auto my-3 h-5 w-5 text-center">
39+
<HoppSmartSpinner />
40+
</div>
41+
</td>
42+
</slot>
43+
</tr>
44+
45+
<tr v-else-if="!list.length">
46+
<slot name="empty-state">
47+
<td :colspan="columnSpan" class="py-3 text-center">
48+
<p>No data available</p>
49+
</td>
50+
</slot>
51+
</tr>
52+
53+
<template v-else>
3154
<tr
32-
class="border-b border-dividerDark bg-primaryLight text-left text-sm text-secondary"
55+
v-for="(rowData, rowIndex) in workingList"
56+
:key="rowIndex"
57+
class="rounded-xl text-secondaryDark hover:cursor-pointer hover:bg-divider"
58+
:class="{ 'divide-x divide-divider': showYBorder }"
59+
@click="onRowClicked(rowData)"
3360
>
34-
<th v-if="selectedRows" class="w-24">
61+
<td v-if="selectedRows">
3562
<input
36-
ref="selectAllCheckbox"
3763
type="checkbox"
38-
:checked="areAllRowsSelected"
39-
:disabled="loading"
64+
:checked="isRowSelected(rowData)"
4065
class="flex h-full w-full items-center justify-center"
41-
@click.stop="toggleAllRows"
66+
@click.stop="toggleRow(rowData)"
4267
/>
43-
</th>
44-
<slot name="head">
45-
<th
46-
v-for="th in headings"
47-
:key="th.key"
48-
scope="col"
49-
class="px-6 py-3"
68+
</td>
69+
<slot name="body" :row="rowData">
70+
<td
71+
v-for="cellHeading in headings"
72+
:key="cellHeading.key"
73+
class="px-4 py-2"
74+
@click="!cellHeading.preventClick && onRowClicked(rowData)"
5075
>
51-
{{ th.label ?? th.key }}
52-
</th>
53-
</slot>
54-
</tr>
55-
</thead>
56-
57-
<tbody class="divide-y divide-divider">
58-
<tr v-if="loading">
59-
<slot name="loading-state">
60-
<td :colspan="columnSpan">
61-
<div class="mx-auto my-3 h-5 w-5 text-center">
62-
<HoppSmartSpinner />
63-
</div>
64-
</td>
65-
</slot>
66-
</tr>
67-
68-
<tr v-else-if="!list.length">
69-
<slot name="empty-state">
70-
<td :colspan="columnSpan" class="py-3 text-center">
71-
<p>No data available</p>
76+
<!-- Dynamic column slot -->
77+
<slot :name="cellHeading.key" :item="rowData">
78+
<!-- Generic implementation of the column -->
79+
<div class="flex flex-col truncate">
80+
<span class="truncate">
81+
{{ rowData[cellHeading.key] ?? "-" }}
82+
</span>
83+
</div>
84+
</slot>
7285
</td>
7386
</slot>
7487
</tr>
75-
76-
<template v-else>
77-
<tr
78-
v-for="(rowData, rowIndex) in workingList"
79-
:key="rowIndex"
80-
class="rounded-xl text-secondaryDark hover:cursor-pointer hover:bg-divider"
81-
:class="{ 'divide-x divide-divider': showYBorder }"
82-
@click="onRowClicked(rowData)"
83-
>
84-
<td v-if="selectedRows">
85-
<input
86-
type="checkbox"
87-
:checked="isRowSelected(rowData)"
88-
class="flex h-full w-full items-center justify-center"
89-
@click.stop="toggleRow(rowData)"
90-
/>
91-
</td>
92-
<slot name="body" :row="rowData">
93-
<td
94-
v-for="cellHeading in headings"
95-
:key="cellHeading.key"
96-
class="px-4 py-2"
97-
@click="!cellHeading.preventClick && onRowClicked(rowData)"
98-
>
99-
<!-- Dynamic column slot -->
100-
<slot :name="cellHeading.key" :item="rowData">
101-
<!-- Generic implementation of the column -->
102-
<div class="flex flex-col truncate">
103-
<span class="truncate">
104-
{{ rowData[cellHeading.key] ?? "-" }}
105-
</span>
106-
</div>
107-
</slot>
108-
</td>
109-
</slot>
110-
</tr>
111-
</template>
112-
</tbody>
113-
</table>
114-
</div>
88+
</template>
89+
</tbody>
90+
</table>
11591
</div>
11692
</template>
11793

11894
<script lang="ts" setup>
11995
import { useVModel } from "@vueuse/core"
12096
import { isEqual } from "lodash-es"
121-
import { computed, ref, watch } from "vue"
122-
123-
import IconLeft from "~icons/lucide/arrow-left"
124-
import IconRight from "~icons/lucide/arrow-right"
125-
97+
import { computed, ref, watch, watchEffect } from "vue"
12698
import { HoppSmartSpinner } from ".."
127-
import { HoppButtonSecondary } from "../button"
12899
129100
export type CellHeading = {
130101
key: string
@@ -143,19 +114,16 @@ const props = withDefaults(
143114
/** The headings of the table */
144115
headings?: CellHeading[]
145116
117+
/** Contains the rows selected */
146118
selectedRows?: Item[]
119+
147120
/** Whether to enable sorting */
148121
sort?: {
149122
/** The key to sort the list by */
150123
key: string
151124
direction: Direction
152125
}
153126
154-
/** Whether to enable pagination */
155-
pagination?: {
156-
totalPages: number
157-
}
158-
159127
/** Whether to show a loading spinner */
160128
loading?: boolean
161129
}>(),
@@ -171,31 +139,8 @@ const emit = defineEmits<{
171139
(event: "onRowClicked", item: Item): void
172140
(event: "update:list", list: Item[]): void
173141
(event: "update:selectedRows", selectedRows: Item[]): void
174-
(event: "pageNumber", page: number): void
175142
}>()
176143
177-
// Pagination functionality
178-
const page = ref(1)
179-
180-
enum PageDirection {
181-
Previous,
182-
Next,
183-
}
184-
185-
const changePage = (direction: PageDirection) => {
186-
const isPrevious = direction === PageDirection.Previous
187-
188-
const isValidPreviousAction = isPrevious && page.value > 1
189-
const isValidNextAction =
190-
!isPrevious && page.value < props.pagination!.totalPages
191-
192-
if (isValidNextAction || isValidPreviousAction) {
193-
page.value += isPrevious ? -1 : 1
194-
195-
emit("pageNumber", page.value)
196-
}
197-
}
198-
199144
// The working version of the list that is used to perform operations upon
200145
const workingList = useVModel(props, "list", emit)
201146
@@ -259,6 +204,14 @@ const areAllRowsSelected = computed(() => {
259204
})
260205
})
261206
207+
watchEffect(() => {
208+
if (selectedRows.value?.length === 0) {
209+
workingList.value.forEach((item) => {
210+
item.selected = false
211+
})
212+
}
213+
})
214+
262215
// Sort List by key and direction which can set to ascending or descending
263216
export type Direction = "ascending" | "descending"
264217

src/stories/Table.story.vue

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,14 @@
44
<HoppSmartTable
55
:headings="headings"
66
:loading="loading"
7-
:list="finalList"
7+
:list="list"
88
:selected-rows="selectedRows"
9-
:pagination="{ totalPages: 2 }"
10-
@page-number="handlePageChange"
11-
>
12-
</HoppSmartTable>
9+
/>
1310
</Variant>
1411

1512
<!-- Custom implementation of the Table -->
1613
<Variant title="Custom">
17-
<HoppSmartTable :loading="loading" :list="finalList">
14+
<HoppSmartTable :loading="loading" :list="list">
1815
<template #head>
1916
<th
2017
v-for="heading in headings"
@@ -60,7 +57,6 @@
6057
:list="extensionList"
6158
:selected-rows="selectedRows"
6259
:sort="{ key: 'name', direction: sortDirection }"
63-
@page-number="handlePageChange"
6460
>
6561
<template #extension>
6662
<div class="flex">
@@ -88,7 +84,6 @@
8884

8985
<script setup lang="ts">
9086
import { computed, onMounted, ref, Ref } from "vue"
91-
9287
import { CellHeading, Direction } from "~/components/smart/Table.vue"
9388
import IconArrowUpDown from "~icons/lucide/arrow-up-down"
9489
import { HoppButtonPrimary, HoppSmartInput } from ".."
@@ -111,10 +106,9 @@ const headings: CellHeading[] = [
111106
112107
const loading = ref(false)
113108
114-
const finalList = ref<List[]>([])
115109
const selectedRows = ref<List[]>([])
116110
117-
const primaryList: List[] = [
111+
const list: List[] = [
118112
{
119113
id: "123456",
120114
name: "Walter",
@@ -129,39 +123,15 @@ const primaryList: List[] = [
129123
},
130124
]
131125
132-
const secondaryList: List[] = [
133-
{
134-
id: "123457",
135-
name: "Gus",
136-
members: 20,
137-
role: "CEO",
138-
},
139-
{
140-
id: "123458",
141-
name: "Mike",
142-
members: 15,
143-
role: "Security",
144-
},
145-
]
146-
147126
onMounted(async () => {
148127
loading.value = true
149128
150129
// Simulate network call
151130
await new Promise((resolve) => setTimeout(resolve, 1000))
152131
153-
finalList.value = primaryList
154132
loading.value = false
155133
})
156134
157-
const handlePageChange = (pageNumber: number) => {
158-
if (pageNumber === 1) {
159-
finalList.value = primaryList
160-
} else {
161-
finalList.value = secondaryList
162-
}
163-
}
164-
165135
const sortDirection: Ref<Direction> = ref("ascending")
166136
167137
const toggleSortDirection = () => {
@@ -172,7 +142,7 @@ const toggleSortDirection = () => {
172142
const searchQuery = ref("")
173143
174144
const extensionList = computed(() => {
175-
return primaryList.filter((item) => {
145+
return list.filter((item) => {
176146
return Object.values(item).some((value) =>
177147
value
178148
.toString()

0 commit comments

Comments
 (0)