From 8259c387e596dc81529a02b8fb2aad2d1ba91617 Mon Sep 17 00:00:00 2001
From: bytedream <bytedream@protonmail.com>
Date: Tue, 29 Aug 2023 14:23:06 +0200
Subject: [PATCH] make admin users table resizable

---
 src/lib/components/utils.ts         | 14 +++--
 src/routes/admin/admin/+page.svelte | 14 +++--
 src/routes/admin/users/+page.svelte | 83 +++++++++++++++++++++--------
 3 files changed, 79 insertions(+), 32 deletions(-)

diff --git a/src/lib/components/utils.ts b/src/lib/components/utils.ts
index 9bb5bc0..b417c64 100644
--- a/src/lib/components/utils.ts
+++ b/src/lib/components/utils.ts
@@ -21,17 +21,21 @@ export function resizeTableColumn(event: MouseEvent, dragOffset: number) {
 
 		const table = element.parentElement!.parentElement!.parentElement as HTMLTableElement;
 		let resizeRow: HTMLTableRowElement;
-		if (table.tBodies[0].rows[0].hidden) {
-			resizeRow = table.rows[0];
+		if (table.tBodies[0].rows[0].hasAttribute('resize-row')) {
+			resizeRow = table.tBodies[0].rows[0];
 		} else {
 			resizeRow = table.tBodies[0].insertRow(0);
-			resizeRow.hidden = true;
+			resizeRow.setAttribute('resize-row', '');
+			resizeRow.style.height = '0';
+			resizeRow.style.border = '0';
+			resizeRow.style.overflow = 'hidden';
 			for (let i = 0; i < table.rows[0].cells.length; i++) {
-				resizeRow.insertCell();
+				const cell = resizeRow.insertCell();
+				cell.style.padding = '0';
 			}
 
 			// insert an additional to keep the zebra in place pattern which might be applied
-			const zebraGhostRow = table.tBodies[0].insertRow(0);
+			const zebraGhostRow = table.tBodies[0].insertRow(1);
 			zebraGhostRow.hidden = true;
 		}
 
diff --git a/src/routes/admin/admin/+page.svelte b/src/routes/admin/admin/+page.svelte
index 61d7cdb..7ea23d1 100644
--- a/src/routes/admin/admin/+page.svelte
+++ b/src/routes/admin/admin/+page.svelte
@@ -196,17 +196,21 @@
 			</tr>
 		{/each}
 		<tr>
-			<td>{data.admins.length + 1}</td>
-			<td><Input type="text" bind:value={newAdminUsername} size="sm" /></td>
-			<td><Input type="password" bind:value={newAdminPassword} size="sm" /></td>
-			<td
+			<td on:mousedown={(e) => resizeTableColumn(e, 5)}>{data.admins.length + 1}</td>
+			<td on:mousedown={(e) => resizeTableColumn(e, 5)}
+				><Input type="text" bind:value={newAdminUsername} size="sm" /></td
+			>
+			<td on:mousedown={(e) => resizeTableColumn(e, 5)}
+				><Input type="password" bind:value={newAdminPassword} size="sm" /></td
+			>
+			<td on:mousedown={(e) => resizeTableColumn(e, 5)}
 				><Badges
 					bind:value={newAdminPermissions}
 					available={allPermissionBadges}
 					disabled={!permissions.adminWrite()}
 				/></td
 			>
-			<td>
+			<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
 				<span
 					class="w-min"
 					class:cursor-not-allowed={!permissions.adminWrite() ||
diff --git a/src/routes/admin/users/+page.svelte b/src/routes/admin/users/+page.svelte
index 3ee457d..ffe5be5 100644
--- a/src/routes/admin/users/+page.svelte
+++ b/src/routes/admin/users/+page.svelte
@@ -5,7 +5,7 @@
 	import Select from '$lib/components/Input/Select.svelte';
 	import { env } from '$env/dynamic/public';
 	import type { User } from '$lib/server/database';
-	import { buttonTriggeredRequest } from '$lib/components/utils';
+	import { buttonTriggeredRequest, resizeTableColumn } from '$lib/components/utils';
 	import { browser } from '$app/environment';
 
 	export let data: PageData;
@@ -135,7 +135,7 @@
 				<tr class="[&>th]:bg-base-100 [&>th]:z-[1] [&>th]:sticky [&>th]:top-0">
 					<th />
 					{#each headers as header}
-						<th>
+						<th on:mousedown={(e) => resizeTableColumn(e, 5)}>
 							<button
 								class="flex items-center"
 								on:click={() => {
@@ -161,22 +161,36 @@
 					{#await currentPageUsersRequest}
 						{#each Array(usersPerPage) as _, i}
 							<tr class="animate-pulse text-transparent">
-								<td>{i + 1}</td>
-								<td><Input type="text" disabled={true} size="sm" /></td>
-								<td><Input type="text" disabled={true} size="sm" /></td>
-								<td><Input type="date" disabled={true} size="sm" /></td>
-								<td><Input type="tel" disabled={true} size="sm" /></td>
-								<td><Input type="text" disabled={true} size="sm" /></td>
-								<td
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>{i + 1}</td>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
+									><Input type="text" disabled={true} size="sm" /></td
+								>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
+									><Input type="text" disabled={true} size="sm" /></td
+								>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
+									><Input type="date" disabled={true} size="sm" /></td
+								>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
+									><Input type="tel" disabled={true} size="sm" /></td
+								>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
+									><Input type="text" disabled={true} size="sm" /></td
+								>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
 									><Select id="edition" disabled={true} size="sm">
 										<option value="java">Java Edition</option>
 										<option value="bedrock">Bedrock Edition</option>
 										<option value="cracked">Java cracked</option>
 									</Select></td
 								>
-								<td><Input type="text" disabled={true} size="sm" /></td>
-								<td><Input type="text" disabled={true} size="sm" /></td>
-								<td
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
+									><Input type="text" disabled={true} size="sm" /></td
+								>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
+									><Input type="text" disabled={true} size="sm" /></td
+								>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
 									><div class="flex gap-1">
 										<button class="btn btn-sm btn-square" disabled />
 									</div></td
@@ -186,14 +200,14 @@
 					{:then _}
 						{#each currentPageUsers as user, i}
 							<tr>
-								<td>{i + 1}</td>
-								<td>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>{i + 1}</td>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
 									<Input type="text" bind:value={user.firstname} disabled={!user.edit} size="sm" />
 								</td>
-								<td>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
 									<Input type="text" bind:value={user.lastname} disabled={!user.edit} size="sm" />
 								</td>
-								<td>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
 									<Input
 										type="date"
 										value={new Date(user.birthday).toISOString().split('T')[0]}
@@ -202,23 +216,23 @@
 										size="sm"
 									/>
 								</td>
-								<td>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
 									<Input type="tel" bind:value={user.telephone} disabled={!user.edit} size="sm" />
 								</td>
-								<td>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
 									<Input type="text" bind:value={user.username} disabled={!user.edit} size="sm" />
 								</td>
-								<td>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
 									<Select id="edition" bind:value={user.playertype} disabled={!user.edit} size="sm">
 										<option value="java">Java Edition</option>
 										<option value="bedrock">Bedrock Edition</option>
 										<option value="cracked">Java cracked</option>
 									</Select>
 								</td>
-								<td>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
 									<Input type="text" bind:value={user.password} disabled={!user.edit} size="sm" />
 								</td>
-								<td>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
 									<Input
 										id="uuid"
 										type="text"
@@ -227,7 +241,7 @@
 										size="sm"
 									/>
 								</td>
-								<td>
+								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
 									<div class="flex gap-1">
 										{#if user.edit}
 											<button
@@ -288,3 +302,28 @@
 		</div>
 	</div>
 </div>
+
+<style lang="scss">
+	thead tr th,
+	tbody tr td {
+		@apply relative;
+
+		&:not(:first-child) {
+			@apply border-l-[1px] border-dashed;
+
+			&::before {
+				@apply absolute left-0 bottom-0 h-full w-[5px] cursor-col-resize;
+				content: '';
+			}
+		}
+
+		&:not(:last-child) {
+			@apply border-r-[1px] border-dashed border-base-300;
+
+			&::after {
+				@apply absolute right-0 bottom-0 h-full w-[5px] cursor-col-resize;
+				content: '';
+			}
+		}
+	}
+</style>