import { platform } from '@tauri-apps/plugin-os' import type { RouteLocationRawI18n } from 'vue-router' /* export const bytesToBase64DataUrlAsync = async ( bytes: Uint8Array, type = 'application/octet-stream', ) => { return await new Promise((resolve, reject) => { const reader = Object.assign(new FileReader(), { onload: () => resolve(reader.result), onerror: () => reject(reader.error), }) reader.readAsDataURL(new File([new Blob([bytes])], '', { type })) }) } */ export const blobToImageAsync = (blob: Blob): Promise => { return new Promise((resolve) => { console.log('transform blob', blob) const url = URL.createObjectURL(blob) const img = new Image() img.onload = () => { URL.revokeObjectURL(url) resolve(img) } img.src = url }) } export const readableFileSize = (sizeInByte: number | string = 0) => { if (!sizeInByte) { return '0 KB' } const size = typeof sizeInByte === 'string' ? parseInt(sizeInByte) : sizeInByte const sizeInKb = size / 1024 const sizeInMb = sizeInKb / 1024 const sizeInGb = sizeInMb / 1024 const sizeInTb = sizeInGb / 1024 if (sizeInTb > 1) return `${sizeInTb.toFixed(2)} TB` if (sizeInGb > 1) return `${sizeInGb.toFixed(2)} GB` if (sizeInMb > 1) return `${sizeInMb.toFixed(2)} MB` return `${sizeInKb.toFixed(2)} KB` } export const getSingleRouteParam = ( param: string | string[] | undefined, ): string => { const _param = Array.isArray(param) ? (param.at(0) ?? '') : (param ?? '') //console.log('getSingleRouteParam found:', _param, param) return decodeURIComponent(_param) } export const isRouteActive = ( to: RouteLocationRawI18n, exact: boolean = false, ) => computed(() => { const found = useRouter() .getRoutes() .find((route) => route.name === useLocaleRoute()(to)?.name) //console.log('found route', found, useRouter().currentRoute.value, to); return exact ? found?.name === useRouter().currentRoute.value.name : found?.name === useRouter().currentRoute.value.name || found?.children.some( (child) => child.name === useRouter().currentRoute.value.name, ) }) export const isKey = (x: T, k: PropertyKey): k is keyof T => { return k in x } export const filterAsync = async ( arr: T[], predicate: (value: T, index: number, array: T[]) => Promise, ) => { // 1. Mappe jedes Element auf ein Promise, das zu true/false auflöst const results = await Promise.all(arr.map(predicate)) // 2. Filtere das ursprüngliche Array basierend auf den Ergebnissen return arr.filter((_value, index) => results[index]) } export const stringToHex = (str: string) => str .split('') .map((char) => char.charCodeAt(0).toString(16).padStart(2, '0')) .join('') // Join array into a single string export const hexToString = (hex: string) => { if (!hex) return '' const parsedValue = hex .match(/.{1,2}/g) // Split hex into pairs ?.map((byte) => String.fromCharCode(parseInt(byte, 16))) // Convert hex to char .join('') // Join array into a single string return parsedValue ? parsedValue : '' } export const getContrastingTextColor = ( hexColor?: string | null, ): 'black' | 'white' => { if (!hexColor) { return 'black' // Fallback } // Entferne das '#' vom Anfang let color = hexColor.startsWith('#') ? hexColor.slice(1) : hexColor // Handle Kurzform-Hex-Werte (z.B. "F0C" -> "FF00CC") if (color.length === 3) { color = color .split('') .map((char) => char + char) .join('') } if (color.length !== 6) { return 'black' // Fallback für ungültige Farben } // Konvertiere Hex zu RGB const r = parseInt(color.substring(0, 2), 16) const g = parseInt(color.substring(2, 4), 16) const b = parseInt(color.substring(4, 6), 16) // Berechne die wahrgenommene Luminanz nach der WCAG-Formel. // Werte von 0 (schwarz) bis 255 (weiß). const luminance = 0.299 * r + 0.587 * g + 0.114 * b // Wähle die Textfarbe basierend auf einem Schwellenwert. // Ein Wert > 186 wird oft als "hell" genug für schwarzen Text angesehen. return luminance > 186 ? 'black' : 'white' } /** * Eine "Type Guard"-Funktion, die prüft, ob ein Wert ein Objekt (aber nicht null) ist. * Wenn sie `true` zurückgibt, weiß TypeScript, dass der Wert sicher als Objekt behandelt werden kann. * @param value Der zu prüfende Wert vom Typ `unknown`. * @returns {boolean} `true`, wenn der Wert ein Objekt ist. */ export const isObject = (value: unknown): value is Record => { return typeof value === 'object' && value !== null } /** * Führt einen typsicheren, tiefen Vergleich (deep comparison) von zwei Werten durch. * Gibt `true` zurück, wenn die Werte als gleich angesehen werden. * * @param valueA Der erste Wert für den Vergleich. * @param valueB Der zweite Wert für den Vergleich. * @returns {boolean} `true`, wenn die Werte gleich sind, andernfalls `false`. */ export const areObjectsEqual = (valueA: unknown, valueB: unknown): boolean => { console.log('areObjectsEqual', valueA, valueB) // 1. Schneller Check für exakt die gleiche Referenz oder primitive Gleichheit if (valueA === valueB) { return true } // DEINE SONDERREGEL: Behandle `null` und einen leeren String `""` als gleichwertig. const areNullAndEmptyString = (valueA === null && valueB === '') || (valueA === '' && valueB === null) if (areNullAndEmptyString) { return true } // 2. Nutzen der Type Guard: Wenn beide Werte keine Objekte sind, // und die vorherigen Checks fehlschlugen, sind sie ungleich. if (!isObject(valueA) || !isObject(valueB)) { console.log('areObjectsEqual no objects', valueA, valueB) return false } // Ab hier weiß TypeScript dank der Type Guard, dass valueA und valueB Objekte sind. // 3. Holen der Schlüssel und Vergleich der Anzahl const keysA = Object.keys(valueA) const keysB = Object.keys(valueB) if (keysA.length !== keysB.length) { console.log('areObjectsEqual length') return false } // 4. Iteration über alle Schlüssel und rekursiver Vergleich der Werte for (const key of keysA) { // Prüfen, ob der Schlüssel auch im zweiten Objekt überhaupt existiert if (!keysB.includes(key)) { console.log('areObjectsEqual keys') return false } // Die Werte der Schlüssel sind wieder `unknown`, daher nutzen wir Rekursion. const nestedValueA = valueA[key] const nestedValueB = valueB[key] // Wenn der rekursive Aufruf für einen der Werte `false` zurückgibt, // sind die gesamten Objekte ungleich. if (!areObjectsEqual(nestedValueA, nestedValueB)) { console.log('areObjectsEqual nested') return false } } // 5. Wenn die Schleife durchläuft, sind die Objekte gleich return true } export const getFileName = (fullPath: string) => { const seperator = platform() === 'windows' ? '\\' : '/' return fullPath.split(seperator).pop() }