From 8450a9a7eb413ee27a37992f033e703625c08430 Mon Sep 17 00:00:00 2001
From: Corban-Lee Jones
Date: Thu, 24 Apr 2025 01:36:39 +0100
Subject: [PATCH] chore: working on datatables implementation for feeds
---
src/client/public/css/main.css | 26 ++++++
src/client/typescript/guild/feeds.ts | 122 ++++++++++++++++++++++++++-
src/client/typescript/main.ts | 40 ++++++++-
src/client/views/guild/feeds.ejs | 20 ++---
4 files changed, 190 insertions(+), 18 deletions(-)
diff --git a/src/client/public/css/main.css b/src/client/public/css/main.css
index 9b1d885..fff18cf 100644
--- a/src/client/public/css/main.css
+++ b/src/client/public/css/main.css
@@ -37,6 +37,32 @@
display: none !important;
}
+.cj-table {
+ @apply min-w-full divide-y divide-gray-200 dark:divide-neutral-700;
+}
+
+.cj-thead {
+ @apply border-none bg-gray-50 dark:bg-neutral-800;
+}
+
+.cj-table-checkbox {
+ @apply form-checkbox shrink-0 disabled:opacity-50 rounded-sm
+ text-blue-600 focus:ring-blue-500 border-gray-300
+ dark:bg-neutral-800 dark:border-neutral-600 dark:checked:bg-blue-500
+ dark:checked:border-blue-500 dark:focus:ring-offset-gray-800;
+}
+
+.cj-table-link {
+ @apply block px-6 py-4 text-blue-500 hover:text-blue-600 focus:text-blue-600
+ dark:text-blue-400 dark:hover:text-blue-500 dark:focus:text-blue-500
+ text-nowrap cursor-pointer
+}
+
+.cj-table-text {
+ @apply text-sm text-gray-500 dark:text-neutral-500 text-nowrap;
+}
+
+
/* Layout Sidebar */
.sidebar-btn {
diff --git a/src/client/typescript/guild/feeds.ts b/src/client/typescript/guild/feeds.ts
index eb841e5..6ec0040 100644
--- a/src/client/typescript/guild/feeds.ts
+++ b/src/client/typescript/guild/feeds.ts
@@ -1,8 +1,10 @@
+import "preline";
import $ from "jquery";
import DataTable from "datatables.net";
import HSDropdown from "@preline/dropdown";
import HSDataTable, { IDataTableOptions } from "@preline/datatable";
import { ConfigColumnDefs, AjaxSettings } from "datatables.net-dt";
+import { formatTimestamp } from "../main";
// Fix dependency bugs with preline
(window as any).DataTable = DataTable;
@@ -21,21 +23,133 @@ const emptyTableHtml: string = `
-
`;
-const columnDefs: ConfigColumnDefs[] = [];
+const columnDefs: ConfigColumnDefs[] = [
+ // Select checkbox column
+ {
+ target: 0,
+ orderable: false,
+ searchable: false,
+ render(_data: unknown, _type: unknown, row: any) { return `
+
+
+
+
+ |
+ `}
+ },
+ {
+ target: 1,
+ data: "name",
+ orderable: true,
+ searchable: true,
+ render(data: string) { return `
+
+
+ ${data}
+
+ |
+ `}
+ },
+ {
+ target: 2,
+ data: "url",
+ orderable: true,
+ searchable: true,
+ render(data: string) { return `
+
+
+ ${data}
+
+ |
+ `}
+ },
+ {
+ target: 3,
+ data: "channels",
+ orderable: false,
+ searchable: false,
+ render(data: string) {
+ return `${data}`
+ }
+ },
+ {
+ target: 4,
+ data: "filters",
+ orderable: false,
+ searchable: false,
+ render(data: string) { return `
+
+
+
+ ${data}
+
+
+ |
+ `}
+ },
+ {
+ target: 5,
+ data: "message_style",
+ orderable: true,
+ searchable: true,
+ render(data: string) { return `
+
+
+
+ ${data}
+
+
+ |
+ `}
+ },
+ {
+ target: 6,
+ data: "created_at",
+ orderable: true,
+ searchable: false,
+ render(data: string) { return `
+
+
+
+ ${formatTimestamp(data)}
+
+
+ |
+ `}
+ },
+ {
+ target: 7,
+ data: "active",
+ orderable: true,
+ searchable: false,
+ render(data: string) { return `
+
+
+
+ ${data}
+
+
+ |
+ `}
+ }
+];
const ajaxSettings: AjaxSettings = {
- url: ``,
+ url: `/guild/${1204426362794811453}/feeds/api/datatable`,
dataSrc: "data",
data: (data: unknown) => {
if (data === undefined) return;
diff --git a/src/client/typescript/main.ts b/src/client/typescript/main.ts
index f1376fd..aed3f84 100644
--- a/src/client/typescript/main.ts
+++ b/src/client/typescript/main.ts
@@ -1,4 +1,36 @@
-import $ from "jquery";
-$(document).ready(() => {
- console.log("ready!");
-});
\ No newline at end of file
+// Preline: necessary for header events.
+window.addEventListener("load", () => {
+ const inputs = document.querySelectorAll('.dt-container thead input');
+
+ inputs.forEach(input => {
+ (input as HTMLInputElement).addEventListener("keydown", (event: KeyboardEvent) => {
+ if ((event.metaKey || event.ctrlKey) && event.key === "a") {
+ (event.target as HTMLInputElement).select();
+ }
+ });
+ });
+});
+
+/**
+ * Formats a given timestamp to one of two formats depending on its age.
+ * @param timestamp
+ * @returns 'DD MMM, HH:mm' if younger than 1 year, else 'DD MMM YYYY'
+ */
+export const formatTimestamp = (timestamp: string | number) => {
+ const date = new Date(
+ typeof timestamp === "string"
+ ? timestamp.replace(" ", "T")
+ : timestamp
+ );
+ const now = new Date();
+ const difference = now.getTime() - date.getTime();
+
+ // Day and short month (example: 21 Oct)
+ const result = `${date.getDate()} ${date.toLocaleString("en-GB", { month: "short" })}`
+
+ // Difference is less than a year: 'DD MMM, HH:mm'
+ // Or, difference is more than a year: 'DD MMM YYYY'
+ return difference < 31536000000
+ ? result + `, ${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`
+ : result + ` ${date.getFullYear()}`;
+}
\ No newline at end of file
diff --git a/src/client/views/guild/feeds.ejs b/src/client/views/guild/feeds.ejs
index f7c0e89..6ec10ab 100644
--- a/src/client/views/guild/feeds.ejs
+++ b/src/client/views/guild/feeds.ejs
@@ -10,17 +10,17 @@
-
+ placeholder header content
-
-
+
+
|
@@ -35,7 +35,7 @@
-
+ |
URL
@@ -46,21 +46,21 @@
|
-
+ |
Channels
|
-
+ |
Filters
|
-
+ |
Style
@@ -71,7 +71,7 @@
|
-
+ |
Created at
@@ -82,7 +82,7 @@
|
-
+ |
Status
|