diff --git a/src/components/ChatBox.tsx b/src/components/ChatBox.tsx
index 2814887..e4ad510 100644
--- a/src/components/ChatBox.tsx
+++ b/src/components/ChatBox.tsx
@@ -174,20 +174,22 @@ export default function ChatBox({ showAllMessagesTab = false, className = "", st
{(!minimized) && (
<>
{showTabs && (
-
- {allTabs.map((key, idx) => (
-
- ))}
+
+
+ {allTabs.map((key, idx) => (
+
+ ))}
+
)}
diff --git a/src/lib/clickhouse/actions.ts b/src/lib/clickhouse/actions.ts
index e843d49..e0dab4c 100644
--- a/src/lib/clickhouse/actions.ts
+++ b/src/lib/clickhouse/actions.ts
@@ -67,14 +67,12 @@ export async function getLatestChatMessages({ limit = 20, before, after, channel
params.channelId = channelId;
}
const whereClause = where.length > 0 ? `WHERE ${where.join(' AND ')}` : '';
- const query = `SELECT ingest_timestamp, origins, mesh_timestamp, path_len, channel_hash, mac, hex(encrypted_message) AS encrypted_message, message_count, origin_path_array FROM meshcore_public_channel_messages ${whereClause} ORDER BY ingest_timestamp DESC LIMIT {limit:UInt32}`;
+ const query = `SELECT ingest_timestamp, mesh_timestamp, channel_hash, mac, hex(encrypted_message) AS encrypted_message, message_count, origin_path_array FROM meshcore_public_channel_messages ${whereClause} ORDER BY ingest_timestamp DESC LIMIT {limit:UInt32}`;
const resultSet = await clickhouse.query({ query, query_params: params, format: 'JSONEachRow' });
const rows = await resultSet.json();
return rows as Array<{
ingest_timestamp: string;
- origins: string[];
mesh_timestamp: string;
- path_len: number;
channel_hash: string;
mac: string;
encrypted_message: string;
diff --git a/src/lib/meshcore-map-nodeutils.ts b/src/lib/meshcore-map-nodeutils.ts
new file mode 100644
index 0000000..43ae923
--- /dev/null
+++ b/src/lib/meshcore-map-nodeutils.ts
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: MIT
+// from https://github.com/recrof/map.meshcore.dev/blob/main/src/node-utils.js
+// Modified to add TypeScript types and support targets earlier than ES2020.
+
+function fnv1aHash(str: string): number {
+ let hash = BigInt(0x811c9dc5);
+ for (let i = 0; i < str.length; i++) {
+ hash = BigInt.asIntN(32, hash ^ BigInt(str.charCodeAt(i)));
+ hash = BigInt.asIntN(32, hash * BigInt(0x01000193));
+ }
+
+ return Number(hash & BigInt(0xFFFFFFFF));
+}
+
+export function getColourForName(name: string, saturation: number = 60, lightness: number = 50): string {
+ const hash = fnv1aHash(name);
+
+ return `hsl(${hash % 360}deg, ${saturation}%, ${lightness}%)`;
+}
+
+export function getNameIconLabel(name: string): string {
+ if (typeof name !== 'string' || name.length === 0) {
+ return ''
+ }
+
+ const match = name.match(/\p{Emoji_Presentation}/u);
+ if (!match) {
+ name = name.trim();
+ const segments = name.split(' ');
+ if (segments.length == 1) {
+ return name.charAt(0);
+ }
+ const firstSegment = segments.at(0);
+ const lastSegment = segments.at(-1);
+ if (firstSegment && lastSegment) {
+ return `${firstSegment[0]}${lastSegment[0]}`;
+ }
+ return '';
+ }
+
+ return match[0];
+}
\ No newline at end of file