madebydanny.uk written in html, css, and a lot of JavaScript I don't understand madeydanny.uk
html css javascript
at main 138 lines 7.4 kB view raw
1(function () { 2 const clients = [ 3 { name: "Bluesky", base: "https://bsky.app/profile/", icon: "https://imrs.madebydanny.uk?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/bsky.webp", cls: "bsky" }, 4 { name: "Blacksky", base: "https://blacksky.community/profile/", icon: "https://imrs.madebydanny.uk?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/blacksky.webp", cls: "blacksky" }, 5 { name: "Anisota", base: "https://anisota.net/profile/", icon: "https://imrs.madebydanny.uk?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/anissota.webp", cls: "anisota" }, 6 { name: "Deer Social", base: "https://deer.social/profile/", icon: "https://imrs.madebydanny.uk?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/deer.webp", cls: "deer" }, 7 { name: "Catsky", base: "https://catsky.social/profile/", icon: "https://imrs.madebydanny.uk?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/catsky.webp", cls: "catsky" }, 8 { name: "Witchsky", base: "https://witchsky.app/profile/", icon: "https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/bitchsky.svg", cls: "bitch" }, 9 { name: "kibun", base: "https://www.kibun.social/users/", icon: "https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/kibun.ico", cls: "bsky" }, 10 { name: "plyr.fm", base: "https://plyr.fm/u/", icon: "https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/plyr.ico", cls: "bsky" }, 11 { name: "Nooki", base: "https://nooki.me/user/", icon: "https://imrs.madebydanny.uk?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/nooki.webp", cls: "nooki" }, 12 { name: "Tangled", base: "https://tangled.org/", icon: "https://imrs.madebydanny.uk?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/tangled.webp", cls: "tangled" }, 13 { name: "Stream Place", base: "https://stream.place/", icon: "https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/splace.ico", cls: "splace" }, 14 { name: "PDSls", base: "https://pdsls.dev/at://", icon: "https://imrs.madebydanny.uk?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/pdsls.webp", cls: "bsky" }, 15 { name: "Red Dwarf", base: "https://reddwarf.app/profile/", icon: "https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/redd.ico", cls: "redd" }, 16 { name: "Deer (aylac fork)", base: "https://deer.aylac.top/profile/", icon: "https://imrs.madebydanny.uk?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/aylac.webp", cls: "deer" }, 17 { name: "Semble", base: "https://semble.so/user/", icon: "https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/semble.svg", cls: "semble" }, 18 { name: "Sky Space", base: "https://skyspace.me/?", icon: "https://imrs.madebydanny.uk?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/skyspace.jpg", cls: "skyspace" }, 19 20 ]; 21 22 const avatarEl = document.getElementById('avatar'); 23 const nameEl = document.getElementById('displayName'); 24 const tagEl = document.getElementById('tagline'); 25 const linksRoot = document.getElementById('links'); 26 const moreClientsRoot = document.getElementById('more-clients'); 27 const showMoreBtn = document.getElementById('show-more'); 28 const tryInput = document.getElementById('try-handle'); 29 const tryBtn = document.getElementById('try-button'); 30 const customInput = document.getElementById('custom-client'); 31 const customBtn = document.getElementById('custom-open'); 32 33 function setText(el, txt){ el.textContent = txt ?? ''; } 34 35 function makeClientLink(c, handle){ 36 const a = document.createElement('a'); 37 a.className = 'link ' + (c.cls || ''); 38 a.href = c.base + encodeURIComponent(handle); 39 a.target = '_blank'; 40 a.rel = 'noopener'; 41 a.setAttribute('aria-label', `Open ${c.name} for ${handle}`); 42 43 const img = document.createElement('img'); 44 img.src = c.icon; 45 img.alt = c.name + ' icon'; 46 img.loading = 'lazy'; 47 48 const span = document.createElement('span'); 49 span.className = 'label'; 50 span.textContent = c.name; 51 52 a.append(img, span); 53 return a; 54 } 55 56 function openCustom(handle){ 57 let url = (customInput.value || '').trim(); 58 if(!url)return; 59 if(!/^https?:\/\//i.test(url))url='https://'+url; 60 url=url.replace(/\/+$/,'')+'/profile/'+encodeURIComponent(handle); 61 window.open(url,'_blank','noopener'); 62 } 63 64 function tryProfile() { 65 let value = (tryInput.value || '').trim(); 66 if (!value) return; 67 68 if (value.startsWith('@')) value = value.slice(1); 69 70 try { 71 const parsed = new URL(value); 72 const parts = parsed.pathname.split('/').filter(Boolean); 73 if (parts.length && (parts[0] === 'profile' || parts[0] === 'actor')) { 74 value = parts[1]; 75 } 76 } catch (_) { } 77 78 const u = new URL(location.href); 79 u.searchParams.set('did', value); 80 location.href = u.toString(); 81 } 82 83 async function loadProfile(){ 84 const params=new URLSearchParams(location.search); 85 const did=params.get('did'); 86 if(!did){ 87 setText(nameEl,'Missing ?did='); 88 setText(tagEl,'Add a DID or handle to view a profile.'); 89 tryBtn.onclick=tryProfile; 90 tryInput.onkeydown=e=>{if(e.key==='Enter')tryProfile()}; 91 return; 92 } 93 try{ 94 const res=await fetch(`https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${encodeURIComponent(did)}`); 95 if(!res.ok)throw new Error('fetch failed'); 96 const data=await res.json(); 97 const handle=data.handle||did; 98 const avatar=data.avatar?`https://imrs.madebydanny.uk?url=${encodeURIComponent(data.avatar)}`:'https://imrs.madebydanny.uk/?url=https://public-cdn.madebydanny.uk/user-content/2025-10-11/1760220038748_cloudflare-brands-solid-full.svg'; 99 100 avatarEl.src=avatar; 101 avatarEl.alt=`${data.displayName||handle} avatar`; 102 setText(nameEl,data.displayName||handle); 103 setText(tagEl,`@${handle} is on the AT Protocol – pick a client to follow them!`); 104 105 linksRoot.innerHTML=''; 106 moreClientsRoot.innerHTML=''; 107 108 const topClients = clients.slice(0, 6); 109 const moreClients = clients.slice(6); 110 111 topClients.forEach(c=>linksRoot.appendChild(makeClientLink(c,handle))); 112 moreClients.forEach(c=>moreClientsRoot.appendChild(makeClientLink(c,handle))); 113 114 if(moreClients.length > 0){ 115 showMoreBtn.style.display = 'block'; 116 showMoreBtn.onclick = function(){ 117 moreClientsRoot.classList.toggle('show'); 118 this.textContent = moreClientsRoot.classList.contains('show') ? 'Show Less' : 'Show More Clients'; 119 }; 120 } 121 122 customBtn.onclick=()=>openCustom(handle); 123 customInput.onkeydown=e=>{if(e.key==='Enter')openCustom(handle)}; 124 tryBtn.onclick=tryProfile; 125 tryInput.onkeydown=e=>{if(e.key==='Enter')tryProfile()}; 126 }catch(e){ 127 nameEl.textContent='Error loading profile'; 128 tagEl.textContent='Check your DID or try again.'; 129 linksRoot.innerHTML=''; 130 moreClientsRoot.innerHTML=''; 131 showMoreBtn.style.display = 'none'; 132 tryBtn.onclick=tryProfile; 133 tryInput.onkeydown=e=>{if(e.key==='Enter')tryProfile()}; 134 } 135 } 136 137 document.addEventListener('DOMContentLoaded',loadProfile); 138})();