utils.js raw
1 import { kindNames } from './constants.js';
2
3 /**
4 * Get human-readable name for a Nostr event kind
5 * @param {number} kind - The event kind number
6 * @returns {string} Human readable kind name
7 */
8 export function getKindName(kind) {
9 return kindNames[kind] || `Kind ${kind}`;
10 }
11
12 /**
13 * Truncate a pubkey for display
14 * @param {string} pubkey - The full pubkey hex string
15 * @returns {string} Truncated pubkey
16 */
17 export function truncatePubkey(pubkey) {
18 if (!pubkey) return "unknown";
19 return pubkey.slice(0, 8) + "..." + pubkey.slice(-8);
20 }
21
22 /**
23 * Truncate content for preview display
24 * @param {string} content - The content to truncate
25 * @param {number} maxLength - Maximum length before truncation
26 * @returns {string} Truncated content
27 */
28 export function truncateContent(content, maxLength = 100) {
29 if (!content) return "";
30 return content.length > maxLength
31 ? content.slice(0, maxLength) + "..."
32 : content;
33 }
34
35 /**
36 * Format a Unix timestamp for display
37 * @param {number} timestamp - Unix timestamp in seconds
38 * @returns {string} Formatted date/time string
39 */
40 export function formatTimestamp(timestamp) {
41 if (!timestamp) return "";
42 return new Date(timestamp * 1000).toLocaleString();
43 }
44
45 /**
46 * Escape HTML special characters to prevent XSS
47 * @param {string} str - String to escape
48 * @returns {string} Escaped string
49 */
50 export function escapeHtml(str) {
51 if (!str) return "";
52 return str
53 .replace(/&/g, "&")
54 .replace(/</g, "<")
55 .replace(/>/g, ">")
56 .replace(/"/g, """)
57 .replace(/'/g, "'");
58 }
59
60 /**
61 * Convert "about" text to safe HTML with line breaks
62 * @param {string} text - The about text
63 * @returns {string} HTML with line breaks
64 */
65 export function aboutToHtml(text) {
66 if (!text) return "";
67 return escapeHtml(text).replace(/\n\n/g, "<br>");
68 }
69
70 /**
71 * Copy text to clipboard with fallback for older browsers
72 * @param {string} text - Text to copy
73 * @returns {Promise<boolean>} Whether copy succeeded
74 */
75 export async function copyToClipboard(text) {
76 try {
77 await navigator.clipboard.writeText(text);
78 return true;
79 } catch (error) {
80 console.error("Failed to copy to clipboard:", error);
81 // Fallback for older browsers
82 try {
83 const textArea = document.createElement("textarea");
84 textArea.value = text;
85 document.body.appendChild(textArea);
86 textArea.select();
87 document.execCommand("copy");
88 document.body.removeChild(textArea);
89 return true;
90 } catch (fallbackError) {
91 console.error("Fallback copy also failed:", fallbackError);
92 return false;
93 }
94 }
95 }
96
97 /**
98 * Show copy feedback on a button element
99 * @param {HTMLElement} button - The button element
100 * @param {boolean} success - Whether copy succeeded
101 */
102 export function showCopyFeedback(button, success = true) {
103 if (!button) return;
104 const originalText = button.textContent;
105 const originalBg = button.style.backgroundColor;
106
107 if (success) {
108 button.textContent = "";
109 button.style.backgroundColor = "#4CAF50";
110 } else {
111 button.textContent = "L";
112 button.style.backgroundColor = "#f44336";
113 }
114
115 setTimeout(() => {
116 button.textContent = originalText;
117 button.style.backgroundColor = originalBg;
118 }, 2000);
119 }
120