Download src/utils/helpers.ts from Jessedbrown/daisy-client: direct link, hf CLI and curl.
- Browser
- Download file 3.17 kB
-
https://huggingface.co/Jessedbrown/daisy-client/resolve/main/src/utils/helpers.ts
- Command line
-
hf download hf://Jessedbrown/daisy-client/src/utils/helpers.ts
-
curl -L -o helpers.ts https://huggingface.co/Jessedbrown/daisy-client/resolve/main/src/utils/helpers.ts
3.17 kB
| import { DEFAULTS } from './constants'; | |
| // Debounce function for search inputs and API calls | |
| export function debounce<T extends (...args: unknown[]) => void>( | |
| func: T, | |
| wait: number = DEFAULTS.SEARCH_DEBOUNCE | |
| ): (...args: Parameters<T>) => void { | |
| let timeout: NodeJS.Timeout; | |
| return (...args: Parameters<T>) => { | |
| clearTimeout(timeout); | |
| timeout = setTimeout(() => func(...args), wait); | |
| }; | |
| } | |
| // Generate unique ID | |
| export function generateId(): string { | |
| return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; | |
| } | |
| // Check if value is empty | |
| export function isEmpty(value: unknown): boolean { | |
| if (value == null) return true; | |
| if (typeof value === 'string') return value.trim().length === 0; | |
| if (Array.isArray(value)) return value.length === 0; | |
| if (typeof value === 'object') return Object.keys(value).length === 0; | |
| return false; | |
| } | |
| // Sleep function for testing and delays | |
| export function sleep(ms: number): Promise<void> { | |
| return new Promise((resolve) => setTimeout(resolve, ms)); | |
| } | |
| // Type-safe object keys | |
| export function objectKeys<T extends Record<string, unknown>>( | |
| obj: T | |
| ): (keyof T)[] { | |
| return Object.keys(obj) as (keyof T)[]; | |
| } | |
| // Safe JSON parse with fallback | |
| export function safeJsonParse<T>(json: string, fallback: T): T { | |
| try { | |
| return JSON.parse(json) as T; | |
| } catch { | |
| return fallback; | |
| } | |
| } | |
| // Deep clone object | |
| export function deepClone<T>(obj: T): T { | |
| if (obj === null || typeof obj !== 'object') return obj; | |
| if (obj instanceof Date) return new Date(obj.getTime()) as T; | |
| if (Array.isArray(obj)) return obj.map(deepClone) as T; | |
| const cloned = {} as T; | |
| for (const key in obj) { | |
| if (Object.prototype.hasOwnProperty.call(obj, key)) { | |
| cloned[key] = deepClone(obj[key]); | |
| } | |
| } | |
| return cloned; | |
| } | |
| // Capitalize first letter | |
| export function capitalize(str: string): string { | |
| return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); | |
| } | |
| // Convert camelCase to kebab-case | |
| export function camelToKebab(str: string): string { | |
| return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase(); | |
| } | |
| // Remove duplicates from array | |
| export function removeDuplicates<T>(array: T[]): T[] { | |
| return [...new Set(array)]; | |
| } | |
| // Group array by key | |
| export function groupBy<T, K extends keyof T>( | |
| array: T[], | |
| key: K | |
| ): Record<string, T[]> { | |
| return array.reduce( | |
| (groups, item) => { | |
| const group = String(item[key]); | |
| groups[group] = groups[group] || []; | |
| groups[group].push(item); | |
| return groups; | |
| }, | |
| {} as Record<string, T[]> | |
| ); | |
| } | |
| // Get full image URL for display | |
| export function getImageUrl(imageUrl: string | null | undefined): string | null { | |
| if (!imageUrl) return null; | |
| // If it's already a full URL, return as is | |
| if (imageUrl.startsWith('http')) return imageUrl; | |
| // If it's a relative URL, prepend the server base URL (not API base URL) | |
| // Images are served directly from the server root, not through the API | |
| const apiBaseUrl = (import.meta.env.VITE_API_BASE_URL as string) || 'http://localhost:3000/api/v1'; | |
| const serverBaseUrl = apiBaseUrl.replace('/api/v1', ''); | |
| return `${serverBaseUrl}${imageUrl}`; | |
| } |