export function isNotEmpty(value) { if (value === null || value === undefined) return false; if (Array.isArray(value)) return value.length > 0; if (typeof value === 'object') return Object.keys(value).length > 0; if (typeof value === 'string') return value.trim() !== ''; return true; // для чисел, булевых и т.п. } export function formatPrice(raw) { if (raw === null || raw === undefined) return ''; const str = String(raw).trim(); const match = str.match(/^([+-]?)(\d+(?:\.\d+)?)/); if (!match) return ''; const sign = match[1] || ''; const num = parseFloat(match[2]); if (isNaN(num) || num === 0) return ''; const formatted = Math.round(num) .toString() .replace(/\B(?=(\d{3})+(?!\d))/g, ' '); return `${sign}${formatted}`; } /** * Получить CSS-переменную DaisyUI OKLH/OKLCH и вернуть HEX для Telegram * @param {string} cssVarName - например '--color-base-100' * @returns {string} #RRGGBB */ export function getCssVarOklchRgb(cssVarName) { // Получаем значение CSS-переменной const cssVar = getComputedStyle(document.documentElement) .getPropertyValue(cssVarName) .trim(); // Проверяем, что это OKLCH const match = cssVar.match(/^oklch\(\s*([\d.]+)%?\s+([\d.]+)\s+([\d.]+)\s*\)$/); if (!match) { console.warn(`CSS variable ${cssVarName} is not a valid OKLCH`); return { r:0, g:0, b:0 }; } // Парсим L, C, H const L = parseFloat(match[1]) / 100; // L в daisyUI в процентах const C = parseFloat(match[2]); const H = parseFloat(match[3]); // --- OKLCH -> OKLab --- const hRad = (H * Math.PI) / 180; const a = C * Math.cos(hRad); const b = C * Math.sin(hRad); const l = L; // --- OKLab -> Linear RGB --- const l_ = l + 0.3963377774 * a + 0.2158037573 * b; const m_ = l - 0.1055613458 * a - 0.0638541728 * b; const s_ = l - 0.0894841775 * a - 1.2914855480 * b; const lCubed = l_ ** 3; const mCubed = m_ ** 3; const sCubed = s_ ** 3; let r = 4.0767416621 * lCubed - 3.3077115913 * mCubed + 0.2309699292 * sCubed; let g = -1.2684380046 * lCubed + 2.6097574011 * mCubed - 0.3413193965 * sCubed; let b_ = -0.0041960863 * lCubed - 0.7034186147 * mCubed + 1.7076147010 * sCubed; // --- Линейный RGB -> sRGB --- const gammaCorrect = c => { c = Math.min(Math.max(c, 0), 1); // обрезаем 0..1 return c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1/2.4) - 0.055; }; r = Math.round(gammaCorrect(r) * 255); g = Math.round(gammaCorrect(g) * 255); b_ = Math.round(gammaCorrect(b_) * 255); // --- Преобразуем в HEX --- const toHex = n => n.toString(16).padStart(2, '0'); return `#${toHex(r)}${toHex(g)}${toHex(b_)}`; } export function deserializeStartParams(serialized) { if (!serialized) { return {}; } // Восстанавливаем стандартные base64 символы let encoded = serialized.replace(/-/g, '+').replace(/_/g, '/'); // Добавляем padding, если нужно const padding = encoded.length % 4; if (padding !== 0) { encoded += '='.repeat(4 - padding); } // Декодируем из base64 let json; try { json = atob(encoded); // btoa / atob стандартные в браузере } catch (e) { throw new Error('Failed to decode base64 string'); } // Парсим JSON let parameters; try { parameters = JSON.parse(json); } catch (e) { throw new Error('Failed to decode JSON: ' + e.message); } if (typeof parameters !== 'object' || parameters === null || Array.isArray(parameters) && !Array.isArray(parameters)) { throw new Error('Decoded value is not an object'); } return parameters; }