1const APP_STORE_URL = 'https://apps.apple.com/us/app/likz-drop/id6779447240'; 2 3export const DOWNLOAD_PLATFORMS = Object.freeze({ 4 windows: Object.freeze({ 5 key: 'windows', 6 name: 'Windows', 7 label: 'Download for Windows', 8 shortLabel: 'Windows', 9 storeLabel: 'Microsoft Store', 10 url: 'https://likz.me/s/get-windows', 11 icon: '#i-monitor', 12 }), 13 macos: Object.freeze({ 14 key: 'macos', 15 name: 'macOS', 16 label: 'Download for macOS', 17 shortLabel: 'macOS', 18 storeLabel: 'App Store', 19 url: APP_STORE_URL, 20 icon: '#i-laptop', 21 }), 22 ios: Object.freeze({ 23 key: 'ios', 24 name: 'iOS', 25 label: 'Download for iPhone & iPad', 26 shortLabel: 'iOS', 27 storeLabel: 'App Store', 28 url: APP_STORE_URL, 29 icon: '#i-smartphone', 30 }), 31 android: Object.freeze({ 32 key: 'android', 33 name: 'Android', 34 label: 'Download for Android', 35 shortLabel: 'Android', 36 storeLabel: 'Google Play', 37 url: 'https://play.google.com/store/apps/details?id=com.likz.app', 38 icon: '#i-smartphone', 39 }), 40 other: Object.freeze({ 41 key: 'other', 42 name: 'All platforms', 43 label: 'Choose your platform', 44 shortLabel: 'Download', 45 storeLabel: 'All platforms', 46 url: '/download.html', 47 icon: '#i-download', 48 }), 49}); 50 51function normalized(value) { 52 return typeof value === 'string' ? value.toLowerCase() : ''; 53} 54 55export function detectDownloadPlatform(environment = {}) { 56 const userAgent = normalized(environment.userAgent); 57 const uaPlatform = normalized(environment.userAgentData?.platform); 58 const legacyPlatform = normalized(environment.platform); 59 const maxTouchPoints = Number(environment.maxTouchPoints || 0); 60 61 const isIPadDesktopMode = legacyPlatform === 'macintel' && maxTouchPoints > 1; 62 if (/iphone|ipad|ipod/.test(userAgent) || isIPadDesktopMode || uaPlatform === 'ios') { 63 return DOWNLOAD_PLATFORMS.ios; 64 } 65 if (uaPlatform === 'android' || userAgent.includes('android')) { 66 return DOWNLOAD_PLATFORMS.android; 67 } 68 if (uaPlatform === 'windows' || userAgent.includes('windows')) { 69 return DOWNLOAD_PLATFORMS.windows; 70 } 71 if (uaPlatform === 'macos' || userAgent.includes('macintosh') || userAgent.includes('mac os x')) { 72 return DOWNLOAD_PLATFORMS.macos; 73 } 74 return DOWNLOAD_PLATFORMS.other; 75} 76 77function updateIcon(scope, icon) { 78 const scopeIsIcon = scope.matches?.('[data-download-icon], [data-detected-platform-icon]'); 79 const use = scopeIsIcon 80 ? scope.querySelector('use') 81 : scope.querySelector('[data-download-icon] use, [data-detected-platform-icon] use'); 82 if (use) use.setAttribute('href', icon); 83} 84 85export function resolveDownloadIcon(platform, { compact = false, hasSymbol = () => true } = {}) { 86 if (compact) return '#i-download'; 87 return hasSymbol(platform.icon) ? platform.icon : '#i-download'; 88} 89 90export function updateDownloadLink(link, platform) { 91 const compact = link.hasAttribute('data-download-compact'); 92 const visibleLabel = compact ? platform.shortLabel : platform.label; 93 link.href = platform.key === 'other' && link.dataset.downloadFallback 94 ? link.dataset.downloadFallback 95 : platform.url; 96 link.dataset.detectedPlatform = platform.key; 97 link.setAttribute('aria-label', platform.label); 98 const label = link.querySelector('[data-download-label]'); 99 if (label) label.textContent = visibleLabel; 100 else { 101 const textNode = Array.from(link.childNodes).find((node) => node.nodeType === 3 && node.textContent.trim()); 102 if (textNode) textNode.textContent = visibleLabel; 103 } 104 const documentRoot = link.ownerDocument; 105 const icon = resolveDownloadIcon(platform, { 106 compact, 107 hasSymbol: (symbol) => Boolean(documentRoot?.querySelector(symbol)), 108 }); 109 updateIcon(link, icon); 110} 111 112export function applyPlatformDownloads(root = document, environment = navigator) { 113 const platform = detectDownloadPlatform(environment); 114 root.querySelectorAll('[data-download-primary]').forEach((link) => updateDownloadLink(link, platform)); 115 116 root.querySelectorAll('[data-detected-platform-name]').forEach((node) => { 117 node.textContent = platform.name; 118 }); 119 root.querySelectorAll('[data-detected-platform-kicker]').forEach((node) => { 120 node.textContent = platform.key === 'other' ? 'Choose a platform' : 'We detected your device'; 121 }); 122 root.querySelectorAll('[data-detected-store-name]').forEach((node) => { 123 node.textContent = platform.storeLabel; 124 }); 125 root.querySelectorAll('[data-detected-platform-icon]').forEach((node) => updateIcon(node, platform.icon)); 126 127 if (root.documentElement) root.documentElement.dataset.downloadPlatform = platform.key; 128 if (root.dispatchEvent && typeof CustomEvent !== 'undefined') { 129 root.dispatchEvent(new CustomEvent('likz:platform-detected', { detail: platform })); 130 } 131 return platform; 132} 133 134if (typeof document !== 'undefined') { 135 const run = () => applyPlatformDownloads(document, navigator); 136 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', run, { once: true }); 137 else run(); 138}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.