21 lines
54 KiB
JavaScript
21 lines
54 KiB
JavaScript
(()=>{var a={data:{appDetailsData:{Software:[],Companion:[]},tagsData:[],tagsById:new Map,dynamicFilterData:[],alternativesById:new Map,companionSoftwareData:null,companionSoftwareById:new Map,licensesData:[],languagesData:[],partners:{sponsorRefs:new Set,partnerRefs:new Set,hosting:new Map,sponsorUrls:new Map,affiliateUrls:new Map},originalOrderMaps:{}},ui:{detailsVisible:!1,showClosedSource:!0,currentDirectory:"Software",selectedTags:[],selectedLicenses:[],selectedLanguages:[],selectedDynamicFilters:[],filteredApps:[],shareBookmarkIDs:null,shareURL:"",starSliderControl:null,forkSliderControl:null},io:{isInitialLoad:!0,currentBatch:0,loading:!1,loadingDirectory:!1,abortController:null}};var e={};function De(){e.categoryRadios=document.querySelectorAll('input[name="category"]'),e.tagFilterTrigger=document.getElementById("tagFilterTrigger"),e.tagFilterDropdown=document.getElementById("tagFilterDropdown"),e.tagFilterOptions=document.getElementById("tagFilterOptions"),e.dynamicFilterTrigger=document.getElementById("dynamicFilterTrigger"),e.dynamicFilterDropdown=document.getElementById("dynamicFilterDropdown"),e.dynamicFilterOptions=document.getElementById("dynamicFilterOptions"),e.dynamicFilterLabel=document.getElementById("dynamicFilterLabel"),e.licenseFilterTrigger=document.getElementById("licenseFilterTrigger"),e.licenseFilterDropdown=document.getElementById("licenseFilterDropdown"),e.licenseFilterOptions=document.getElementById("licenseFilterOptions"),e.languageFilterTrigger=document.getElementById("languageFilterTrigger"),e.languageFilterDropdown=document.getElementById("languageFilterDropdown"),e.languageFilterOptions=document.getElementById("languageFilterOptions"),e.partnersFilterCheckbox=document.getElementById("partnersFilterCheckbox"),e.bookmarksFilterCheckbox=document.getElementById("bookmarksFilterCheckbox"),e.iconsFilterCheckbox=document.getElementById("iconsFilterCheckbox"),e.starSlider=document.getElementById("starSlider"),e.starFill=document.getElementById("starFill"),e.starThumbMin=document.getElementById("starThumbMin"),e.starThumbMax=document.getElementById("starThumbMax"),e.starMinValue=document.getElementById("starMinValue"),e.starMaxValue=document.getElementById("starMaxValue"),e.forkSlider=document.getElementById("forkSlider"),e.forkFill=document.getElementById("forkFill"),e.forkThumbMin=document.getElementById("forkThumbMin"),e.forkThumbMax=document.getElementById("forkThumbMax"),e.forkMinValue=document.getElementById("forkMinValue"),e.forkMaxValue=document.getElementById("forkMaxValue"),e.sortOptions=document.getElementById("sortOptions"),e.searchBox=document.getElementById("searchBox"),e.searchClearButton=document.getElementById("searchClearButton"),e.mobileSearchBox=document.getElementById("mobileSearchBox"),e.mobileSearchClearButton=document.getElementById("mobileSearchClearButton"),e.bookmarkCountBadge=document.getElementById("bookmarkCountBadge"),e.mobileBookmarkCountBadge=document.getElementById("mobileBookmarkCountBadge"),e.mobileFilterBadge=document.getElementById("mobileFilterBadge"),e.mobileSortOptions=document.getElementById("mobileSortOptions"),e.dataContainer=document.getElementById("dataContainer"),e.activeFiltersBar=document.getElementById("activeFiltersBar"),e.toggleDetailsSwitch=document.getElementById("toggleDetailsSwitch"),e.toggleClosedSourceSwitch=document.getElementById("toggleClosedSourceSwitch"),e.shareButton=document.getElementById("shareBookmarksButton"),e.sidebar=document.querySelector(".sidebar"),e.noResultsContainer=document.getElementById("noResultsContainer"),e.noResultsClearButton=document.getElementById("noResultsClearButton"),e.mobileFilterBtn=document.getElementById("mobileFilterBtn"),e.mobileFilterOverlay=document.getElementById("mobileFilterOverlay"),e.mobileFilterClose=document.getElementById("mobileFilterClose"),e.mobileClosedSourceSwitch=document.getElementById("m-toggleClosedSourceSwitch"),e.mobilePartnersCheckbox=document.getElementById("m-partnersFilterCheckbox"),e.mobileBookmarksCheckbox=document.getElementById("m-bookmarksFilterCheckbox"),e.mobileIconsCheckbox=document.getElementById("m-iconsFilterCheckbox"),e.mobileTagFilter=document.getElementById("m-tagFilter"),e.mobileDynamicFilter=document.getElementById("m-dynamicFilter"),e.mobileDynamicFilterLabel=document.getElementById("m-dynamicFilterLabel"),e.mobileLicenseFilter=document.getElementById("m-licenseFilter"),e.mobileLanguageFilter=document.getElementById("m-languageFilter"),e.mobileClearFiltersButton=document.getElementById("mobileClearFiltersButton"),e.mobileClearFiltersContainer=document.getElementById("mobileClearFiltersContainer"),e.mobileCategorySoftware=document.getElementById("m-category-software"),e.mobileCategoryCompanion=document.getElementById("m-category-companion")}var at="prod",rt={dev:"https://selfh.st/static/build/apps/dev/files/",prod:"https://selfhst.github.io/cdn/directory/"},H=rt[at],V={software:H+"software.json",companion:H+"companions.json",tags:H+"tags.json",alternatives:H+"alternatives.json",companionSoftware:H+"companion-software.json",licenses:H+"licenses.json",languages:H+"languages.json",partners:"https://selfh.st/static/build/apps/partners.json"};var se="?ref=selfh.st",G=50,$=30,Ee=150,Ae=150,ce=1e3,Ie=768,Te=480,de=.5,ue=.6,Me=21,Re=18,Oe=16,ee=24,te=20,Ne=280,w={search:"Search",tag:{singular:"Tag",plural:"Tags"},dynamic:{singular:"Alternative",plural:"Alternatives"},license:{singular:"License",plural:"Licenses"},language:{singular:"Language",plural:"Languages"},stars:"Stars",forks:"Forks",partners:"Partners",bookmarks:"Bookmarks",icons:"selfh.st/icons",openSource:"Open Source",clearAll:"Clear all"};function it(t,r){let o;return function(...n){clearTimeout(o),o=setTimeout(()=>t.apply(this,n),r)}}function J(t,r,o){let n=(i,c)=>()=>{c&&(c.checked=i.checked),o?.(i.checked)};t&&t.addEventListener("change",n(t,r)),r&&r.addEventListener("change",n(r,t))}function me(t,r,o,n,i){let c=(u,d)=>()=>{d&&(d.value=u.value),n?.(u.value)},l=u=>i?it(u,i):u;t&&t.addEventListener(o,l(c(t,r))),r&&r.addEventListener(o,l(c(r,t)))}function Ue(t){let r=parseInt(t)||0;return r<1e3?r.toString():(r/1e3).toFixed(0)+"k"}function N(t){return t>=1e3?t.toLocaleString():t.toString()}function fe(t){return!t||t.startsWith("http://")||t.startsWith("https://")?t:"https://"+t}var ot=document.createElement("canvas"),Pe=ot.getContext("2d");function ae(t,r,o="500"){return Pe.font=`${o} ${r}px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`,Pe.measureText(t).width}function F(t,r={}){let o=document.createElement(t);return r.text&&(o.textContent=r.text),r.html&&(o.innerHTML=r.html),r.className&&(o.className=r.className),r.src&&(o.src=r.src),r.alt&&(o.alt=r.alt),r.width&&(o.width=r.width),r.height&&(o.height=r.height),r.href&&(o.href=r.href),r.target&&(o.target=r.target),r.title&&(o.title=r.title),r.dataset&&Object.assign(o.dataset,r.dataset),r.attrs&&Object.entries(r.attrs).forEach(([n,i])=>o.setAttribute(n,i)),o}function qe(t,r,o){o?t.searchParams.set(r,o):t.searchParams.delete(r)}function P(){return JSON.parse(localStorage.getItem("bookmarks"))||[]}var Ve='<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" style="width:1em;height:1em;flex-shrink:0"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></svg>';function _(t,{persistent:r=!1}={}){let o=document.getElementById("app-toast");o&&o.remove();let n=document.createElement("div");n.id="app-toast",n.className="app-toast",n.textContent=t,document.body.appendChild(n),requestAnimationFrame(()=>n.classList.add("app-toast--visible")),r||setTimeout(()=>{n.classList.remove("app-toast--visible"),n.addEventListener("transitionend",()=>n.remove(),{once:!0})},3e3)}async function He(t){a.io.abortController&&a.io.abortController.abort(),a.io.abortController=new AbortController;let r=V[t.toLowerCase()],o=await fetch(r,{signal:a.io.abortController.signal});a.data.appDetailsData[t]=await o.json()}async function pe(t){let r=Je(t);Ge(a.data.tagsData,t),Ye(),await r,je(t)}function $e(){let t=new URLSearchParams(window.location.search);if(!t.has("view"))return null;let r=t.get("view");r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1));let o=r.charAt(0).toUpperCase(),n=r.substring(1);a.ui.shareBookmarkIDs=n.split(",").map(l=>Number(l.trim())).filter(l=>!isNaN(l));let i=o==="C"?"Companion":"Software";a.ui.currentDirectory=i,t.delete("view");let c=t.toString();return window.history.replaceState({},"",window.location.pathname+(c?`?${c}`:"")),i}async function _e(){if(a.data.companionSoftwareData)return;let t=await fetch(V.companionSoftware);a.data.companionSoftwareData=await t.json(),a.data.companionSoftwareById=new Map(a.data.companionSoftwareData.map(r=>[r[0],r]))}async function he(t,r=!1){if(!a.io.loadingDirectory){a.ui.currentDirectory=t,a.io.loadingDirectory=!0,ge(),a.io.currentBatch=0;try{await Promise.all([nt(),He(t)]),a.ui.currentDirectory===t&&(ke(),be(),await pe(t))}catch(o){o.name!=="AbortError"&&(console.error("Error fetching data:",o),e.dataContainer.innerHTML='<div class="error-message">Failed to load apps. Please try again.</div>')}finally{a.io.loadingDirectory=!1}r||ze(),a.io.isInitialLoad=!1}}async function nt(){let t=async u=>{let d=await fetch(u);if(!d.ok)throw new Error(`HTTP ${d.status}`);return d.json()},[r,o,n,i,c]=await Promise.allSettled([t(V.tags),t(V.alternatives),t(V.licenses),t(V.languages),t(V.partners)]),l=(u,d)=>{u.status==="rejected"&&console.error(`Failed to load ${d}:`,u.reason)};if(l(r,"tags"),l(o,"alternatives"),l(n,"licenses"),l(i,"languages"),l(c,"partners"),r.status==="fulfilled"&&(a.data.tagsData=r.value,a.data.tagsById=new Map(a.data.tagsData.map(u=>[u[0],u]))),o.status==="fulfilled"&&(a.data.dynamicFilterData=o.value,a.data.alternativesById=new Map(a.data.dynamicFilterData.map(u=>[u[0],u]))),n.status==="fulfilled"&&(a.data.licensesData=n.value),i.status==="fulfilled"&&(a.data.languagesData=i.value),c.status==="fulfilled"){let u=c.value,d=new Date;u["Self-Hosted Sponsors"]&&u["Self-Hosted Sponsors"].filter(s=>!s.Start||!s.End?!1:d>=new Date(s.Start)&&d<=new Date(s.End)).forEach(s=>{a.data.partners.sponsorRefs.add(s.Reference),s.URL&&a.data.partners.sponsorUrls.set(s.Reference,s.URL)}),u["Self-Hosted Affiliates"]&&u["Self-Hosted Affiliates"].forEach(s=>{s.Reference&&s.URL&&a.data.partners.affiliateUrls.set(s.Reference,s.URL)}),u["Hosting Sponsors"]&&u["Hosting Sponsors"].filter(s=>!s.Start||!s.End?!1:d>=new Date(s.Start)&&d<=new Date(s.End)).forEach(s=>{s.Tiles?.forEach(m=>{a.data.partners.hosting.set(m.Reference,{host:s.Host,url:m.URL,tagline:s.Tagline,icon:s.Icon,linkType:s["Link Type"]})})}),u.Partners&&u.Partners.forEach(s=>a.data.partners.partnerRefs.add(s))}}async function We(t){if(!a.io.loadingDirectory){if(a.data.appDetailsData[t]&&a.data.appDetailsData[t].length>0){Xe(),await pe(t);return}a.io.loadingDirectory=!0,ge(),a.io.currentBatch=0;try{await He(t),a.ui.currentDirectory===t&&(ke(),be(),await pe(t))}catch(r){r.name!=="AbortError"&&(console.error("Error fetching data:",r),e.dataContainer.innerHTML='<div class="error-message">Failed to load apps. Please try again.</div>')}finally{a.io.loadingDirectory=!1}}}function lt(t,r,o){if(!t)return;let n=`${o}-all`,i=t.querySelectorAll(`input[type="checkbox"]:not(#${n})`);for(let l of i)if(l.value===r){l.checked=!1,l.closest(".custom-multiselect-option")?.setAttribute("aria-selected","false");break}if(t.querySelectorAll(`input[type="checkbox"]:not(#${n}):checked`).length===0){let l=t.querySelector(`#${n}`);l&&(l.checked=!0,l.closest(".custom-multiselect-option")?.setAttribute("aria-selected","true"))}}function st(t,r,o,n,i,c){a.ui[t]=a.ui[t].filter(l=>l!==r),lt(o,r,n),B(i,a.ui[t]),c&&c.value===r&&(c.value=""),a.ui.shareBookmarkIDs=null,v(),A(a.ui.currentDirectory),L()}function ct(t,r,o,n,i){if(a.ui[t]=[],r){let c=`${o}-all`;r.querySelectorAll(`input[type="checkbox"]:not(#${c})`).forEach(u=>{u.checked=!1,u.closest(".custom-multiselect-option")?.setAttribute("aria-selected","false")});let l=r.querySelector(`#${c}`);l&&(l.checked=!0,l.closest(".custom-multiselect-option")?.setAttribute("aria-selected","true"))}B(n,a.ui[t]),i&&(i.value=""),a.ui.shareBookmarkIDs=null,v(),A(a.ui.currentDirectory),L()}function dt(){e.searchBox.value="",e.mobileSearchBox&&(e.mobileSearchBox.value=""),a.ui.shareBookmarkIDs=null,v();let t=new URL(window.location.href);t.searchParams.delete("search"),window.history.replaceState({},"",t),L()}function ut(){a.ui.starSliderControl&&a.ui.starSliderControl.reset(),L()}function mt(){a.ui.forkSliderControl&&a.ui.forkSliderControl.reset(),L()}function ye(t,r){t&&(t.checked=!1),r&&(r.checked=!1),a.ui.shareBookmarkIDs=null,v(),A(a.ui.currentDirectory),L()}function ft(){e.toggleClosedSourceSwitch&&(e.toggleClosedSourceSwitch.checked=!0),e.mobileClosedSourceSwitch&&(e.mobileClosedSourceSwitch.checked=!0),a.ui.showClosedSource=!0,localStorage.setItem("showClosedSource","true"),v(),L()}function re(){let t=e.activeFiltersBar;if(!t)return;let r=[],o=e.searchBox?.value.trim();o&&r.push({label:`${w.search}: ${o}`,onClear:dt});let n=5,i=(s,m,p,y,h,f,S)=>{let C=a.ui[p];C.length!==0&&(C.length>n?r.push({label:`${m} (${C.length})`,onClear:()=>ct(p,y,h,f,S)}):C.forEach(g=>r.push({label:`${s}: ${g}`,onClear:()=>st(p,g,y,h,f,S)})))};i(w.tag.singular,w.tag.plural,"selectedTags",e.tagFilterOptions,"tag",e.tagFilterTrigger,e.mobileTagFilter),i(w.dynamic.singular,w.dynamic.plural,"selectedDynamicFilters",e.dynamicFilterOptions,"dynamic",e.dynamicFilterTrigger,e.mobileDynamicFilter),i(w.license.singular,w.license.plural,"selectedLicenses",e.licenseFilterOptions,"license",e.licenseFilterTrigger,e.mobileLicenseFilter),i(w.language.singular,w.language.plural,"selectedLanguages",e.languageFilterOptions,"language",e.languageFilterTrigger,e.mobileLanguageFilter);let c=a.ui.starSliderControl?.getRange(),l=a.ui.starSliderControl?.getValues();if(c&&l&&(l.min>0||l.max<c.max)){let s=l.max>=c.max?`${N(c.max)}+`:N(l.max);r.push({label:`${w.stars}: ${N(l.min)}\u2013${s}`,onClear:ut})}let u=a.ui.forkSliderControl?.getRange(),d=a.ui.forkSliderControl?.getValues();if(u&&d&&(d.min>0||d.max<u.max)){let s=d.max>=u.max?`${N(u.max)}+`:N(d.max);r.push({label:`${w.forks}: ${N(d.min)}\u2013${s}`,onClear:mt})}if(e.partnersFilterCheckbox?.checked&&r.push({label:w.partners,onClear:()=>ye(e.partnersFilterCheckbox,e.mobilePartnersCheckbox)}),e.bookmarksFilterCheckbox?.checked&&r.push({label:w.bookmarks,onClear:()=>ye(e.bookmarksFilterCheckbox,e.mobileBookmarksCheckbox)}),e.iconsFilterCheckbox?.checked&&r.push({label:w.icons,onClear:()=>ye(e.iconsFilterCheckbox,e.mobileIconsCheckbox)}),e.toggleClosedSourceSwitch&&!e.toggleClosedSourceSwitch.checked&&r.push({label:w.openSource,onClear:ft}),t.innerHTML="",r.length!==0&&(r.forEach(s=>{let m=document.createElement("button");m.type="button",m.className="active-filter-chip",m.setAttribute("aria-label",`Remove filter: ${s.label}`);let p=document.createElement("span");p.className="active-filter-chip__label",p.textContent=s.label;let y=document.createElement("span");y.className="active-filter-chip__x",y.setAttribute("aria-hidden","true"),y.textContent="\xD7",m.appendChild(p),m.appendChild(y),m.addEventListener("click",s.onClear),t.appendChild(m)}),r.length>=2)){let s=document.createElement("button");s.type="button",s.className="active-filter-chip active-filter-chip--clear-all",s.setAttribute("aria-label","Clear all filters");let m=document.createElement("span");m.className="active-filter-chip__label",m.textContent=w.clearAll;let p=document.createElement("span");p.className="active-filter-chip__x",p.setAttribute("aria-hidden","true"),p.textContent="\xD7",s.appendChild(m),s.appendChild(p),s.addEventListener("click",X),t.appendChild(s)}}function Ce(t,r){let o=r.querySelector(".bookmark-icon")||r,n=P(),i;n.includes(t)?(n=n.filter(c=>c!==t),o.classList.remove("bookmarked"),i=!1):(n.push(t),o.classList.add("bookmarked"),i=!0),r.setAttribute("aria-pressed",String(i)),localStorage.setItem("bookmarks",JSON.stringify(n)),Q()}function Q(){let r=`(${P().length})`;e.bookmarkCountBadge&&(e.bookmarkCountBadge.textContent=r),e.mobileBookmarkCountBadge&&(e.mobileBookmarkCountBadge.textContent=r)}function A(t){let r=new URL(window.location.href);r.searchParams.delete("view"),t==="Software"?(r.searchParams.delete("directory"),r.searchParams.delete("companion"),r.searchParams.delete("platform")):t==="Companion"&&(r.searchParams.set("directory",t),r.searchParams.delete("platform")),a.ui.selectedTags.length>0?r.searchParams.set("tag",a.ui.selectedTags.join(",")):r.searchParams.delete("tag"),a.ui.selectedLicenses.length>0?r.searchParams.set("license",a.ui.selectedLicenses.join(",")):r.searchParams.delete("license"),a.ui.selectedLanguages.length>0?r.searchParams.set("language",a.ui.selectedLanguages.join(",")):r.searchParams.delete("language"),t==="Software"?(a.ui.selectedDynamicFilters.length>0?r.searchParams.set("alternative",a.ui.selectedDynamicFilters.join(",")):r.searchParams.delete("alternative"),r.searchParams.delete("companion")):t==="Companion"&&(a.ui.selectedDynamicFilters.length>0?r.searchParams.set("companion",a.ui.selectedDynamicFilters.join(",")):r.searchParams.delete("companion"),r.searchParams.delete("alternative")),qe(r,"search",e.searchBox.value.trim()),window.history.replaceState({},"",r)}function Se(t){e.categoryRadios.forEach(r=>{r.checked=r.value===t})}async function xe(t){a.ui.currentDirectory===t||a.io.loadingDirectory||(e.searchBox.value="",e.mobileSearchBox&&(e.mobileSearchBox.value=""),e.sortOptions.value="",e.mobileSortOptions&&(e.mobileSortOptions.value=""),a.ui.currentDirectory=t,a.ui.detailsVisible=!1,e.toggleDetailsSwitch.checked=!1,document.body.classList.remove("details-toggle-active"),Se(t),document.querySelectorAll('input[name="m-category"]').forEach(r=>{r.checked=r.value===t}),await We(t),A(t))}function L(){let t=a.ui.starSliderControl?a.ui.starSliderControl.getRange():null,r=a.ui.forkSliderControl?a.ui.forkSliderControl.getRange():null,o=a.ui.starSliderControl?a.ui.starSliderControl.getValues():null,n=a.ui.forkSliderControl?a.ui.forkSliderControl.getValues():null,i=o&&t&&(o.min>0||o.max<t.max),c=n&&r&&(n.min>0||n.max<r.max),u=[!!e.searchBox.value.trim(),a.ui.selectedTags.length>0,a.ui.selectedDynamicFilters.length>0,a.ui.selectedLicenses.length>0,a.ui.selectedLanguages.length>0,!!(e.sortOptions.value&&e.sortOptions.value!=="default"),!!(e.partnersFilterCheckbox&&e.partnersFilterCheckbox.checked),!!(e.bookmarksFilterCheckbox&&e.bookmarksFilterCheckbox.checked),!!(e.iconsFilterCheckbox&&e.iconsFilterCheckbox.checked),!e.toggleClosedSourceSwitch.checked,!!i,!!c].filter(Boolean).length,d=u>0;e.mobileClearFiltersContainer&&e.mobileClearFiltersContainer.classList.toggle("hidden",!d),e.mobileFilterBadge&&(e.mobileFilterBadge.textContent=u>0?String(u):""),re()}function X(){e.searchBox.value="",a.ui.selectedTags=[],a.ui.selectedLicenses=[],a.ui.selectedLanguages=[],a.ui.selectedDynamicFilters=[],e.dynamicFilterOptions&&e.dynamicFilterOptions.querySelectorAll('input[type="checkbox"]').forEach(r=>r.checked=!1);let t=e.dynamicFilterOptions?.querySelector("#dynamic-all");t&&(t.checked=!0),B(e.dynamicFilterTrigger,a.ui.selectedDynamicFilters),e.tagFilterOptions.querySelectorAll('input[type="checkbox"]').forEach(r=>r.checked=!1),e.licenseFilterOptions.querySelectorAll('input[type="checkbox"]').forEach(r=>r.checked=!1),e.languageFilterOptions.querySelectorAll('input[type="checkbox"]').forEach(r=>r.checked=!1),B(e.tagFilterTrigger,a.ui.selectedTags),B(e.licenseFilterTrigger,a.ui.selectedLicenses),B(e.languageFilterTrigger,a.ui.selectedLanguages),a.ui.starSliderControl&&a.ui.starSliderControl.reset(),a.ui.forkSliderControl&&a.ui.forkSliderControl.reset(),e.sortOptions.value="",e.toggleClosedSourceSwitch.checked=!0,a.ui.showClosedSource=!0,localStorage.setItem("showClosedSource","true"),e.partnersFilterCheckbox&&(e.partnersFilterCheckbox.checked=!1),e.bookmarksFilterCheckbox&&(e.bookmarksFilterCheckbox.checked=!1),e.iconsFilterCheckbox&&(e.iconsFilterCheckbox.checked=!1),e.mobileSearchBox&&(e.mobileSearchBox.value=""),e.mobileSortOptions&&(e.mobileSortOptions.value=""),e.mobileClosedSourceSwitch&&(e.mobileClosedSourceSwitch.checked=!0),e.mobilePartnersCheckbox&&(e.mobilePartnersCheckbox.checked=!1),e.mobileBookmarksCheckbox&&(e.mobileBookmarksCheckbox.checked=!1),e.mobileIconsCheckbox&&(e.mobileIconsCheckbox.checked=!1),e.mobileTagFilter&&(e.mobileTagFilter.value=""),e.mobileDynamicFilter&&(e.mobileDynamicFilter.value=""),e.mobileLicenseFilter&&(e.mobileLicenseFilter.value=""),e.mobileLanguageFilter&&(e.mobileLanguageFilter.value=""),a.ui.shareBookmarkIDs=null,L(),v(),A(a.ui.currentDirectory)}function W(t){let r=t.previousElementSibling;t.classList.remove("active"),r&&(r.classList.remove("active"),r.setAttribute("aria-expanded","false"));let o=t.querySelector(".multiselect-search-input");o&&(o.value="",t.querySelector(".custom-multiselect-options")?.querySelectorAll(".custom-multiselect-option").forEach(n=>{n.style.display=""}))}function ie(t,r){if(!t||!r)return;let o=r.querySelector(".custom-multiselect-options"),n=document.createElement("div");n.className="multiselect-search-wrapper",n.innerHTML='<input type="text" class="multiselect-search-input" placeholder="Search..." aria-label="Search options">',r.insertBefore(n,o);let i=n.querySelector(".multiselect-search-input");i.addEventListener("click",d=>d.stopPropagation());function c(d){let s=d.toLowerCase().trim();o.querySelectorAll(".custom-multiselect-option").forEach(m=>{if(m.classList.contains("all-option")){m.style.display=s?"none":"";return}let p=m.querySelector("label");m.style.display=!s||p&&p.textContent.toLowerCase().includes(s)?"":"none"})}i.addEventListener("input",()=>c(i.value));function l(){return[...o.querySelectorAll(".custom-multiselect-option")].filter(d=>d.style.display!=="none")}function u(){r.classList.add("active"),t.classList.add("active"),t.setAttribute("aria-expanded","true"),requestAnimationFrame(()=>i.focus())}t.addEventListener("click",d=>{d.stopPropagation();let s=r.classList.contains("active");document.querySelectorAll(".custom-multiselect-dropdown.active").forEach(m=>{m!==r&&W(m)}),s?W(r):u()}),t.addEventListener("keydown",d=>{if(d.key==="Enter"||d.key===" "||d.key==="ArrowDown"){if(d.preventDefault(),r.classList.contains("active")||u(),d.key==="ArrowDown"){let s=l();s.length&&s[0].focus()}}else d.key==="Escape"&&W(r)}),i.addEventListener("keydown",d=>{if(d.key==="ArrowDown"){d.preventDefault();let s=l();s.length&&s[0].focus()}else d.key==="ArrowUp"?(d.preventDefault(),t.focus()):d.key==="Escape"&&(W(r),t.focus())}),o.addEventListener("keydown",d=>{let s=l(),m=s.indexOf(document.activeElement);if(m!==-1)if(d.key==="ArrowDown")d.preventDefault(),m<s.length-1&&s[m+1].focus();else if(d.key==="ArrowUp")d.preventDefault(),m>0?s[m-1].focus():i.focus();else if(d.key==="Enter"||d.key===" "){d.preventDefault();let p=s[m].querySelector('input[type="checkbox"]');p&&(p.checked=!p.checked,p.dispatchEvent(new Event("change",{bubbles:!0})))}else d.key==="Escape"&&(W(r),t.focus())})}function pt(){let t=document.createElement("div");t.id="app-tooltip",document.body.appendChild(t);let r=null;function o(n){let i=n.getBoundingClientRect(),c=t.offsetWidth,l=t.offsetHeight,u=i.left+i.width/2-c/2,d=i.bottom+6;u=Math.max(8,Math.min(u,window.innerWidth-c-8)),d+l>window.innerHeight-8&&(d=i.top-l-6),t.style.left=u+"px",t.style.top=d+"px"}document.addEventListener("mouseover",n=>{let i=n.target.closest("[data-tooltip]");i&&(r=i,t.textContent=i.dataset.tooltip,t.classList.add("visible"),o(i))}),document.addEventListener("mouseout",n=>{let i=n.target.closest("[data-tooltip]");i&&(i.contains(n.relatedTarget)||(t.classList.remove("visible"),r=null))}),window.addEventListener("scroll",()=>{r&&o(r)},{passive:!0})}function Qe(){e.dataContainer.addEventListener("click",function(i){let c=i.target.closest(".bookmark-container");if(c&&i.target.closest(".main-layout")){i.stopPropagation();let s=c.dataset.reference;Ce(s,c);return}if(i.target.closest(".partner-tagline-container"))return;let u=i.target.closest("a");if(u){if(u.classList.contains("source-link")||u.classList.contains("tag-link")||u.classList.contains("rss-icon-link"))return;if(u.classList.contains("tag-chip")){i.preventDefault(),i.stopPropagation();let s=u.textContent.trim(),m=e.tagFilterOptions?e.tagFilterOptions.querySelector("#tag-all"):null,p=e.tagFilterOptions?e.tagFilterOptions.querySelectorAll('input[type="checkbox"]:not(#tag-all)'):[],y=!1;p.forEach(h=>{h.value===s?(h.checked=!0,y=!0):h.checked=!1}),m&&(m.checked=!y),a.ui.selectedTags=y?[s]:[],B(e.tagFilterTrigger,a.ui.selectedTags),e.mobileTagFilter&&(e.mobileTagFilter.value=y?s:""),window.scrollY>200&&window.scrollTo({top:0,behavior:"smooth"}),v(),A(a.ui.currentDirectory);return}u.classList.contains("project-name")&&i.preventDefault()}let d=i.target.closest(".tile");if(d)if(Y()){if(i.target.closest(".source-link"))return;let m=d.querySelector(".project-name");m&&m.href&&window.open(m.href,"_blank");return}else{let s=d.querySelector(".project-name");s&&s.href&&window.open(s.href,"_blank")}}),e.categoryRadios.forEach(i=>{i.addEventListener("change",function(){this.checked&&xe(this.value)})}),e.noResultsClearButton&&e.noResultsClearButton.addEventListener("click",X),[e.searchBox,e.sortOptions,e.toggleClosedSourceSwitch].forEach(i=>{i&&(i.addEventListener("change",L),i.addEventListener("input",L))});let t=()=>{a.ui.shareBookmarkIDs=null,v(),A(a.ui.currentDirectory)};me(e.searchBox,e.mobileSearchBox,"input",()=>{if(a.ui.shareBookmarkIDs=null,v(),e.searchBox.value.trim())A(a.ui.currentDirectory);else{let i=new URL(window.location.href);i.searchParams.delete("search"),window.history.replaceState({},"",i)}},Ee);let r=(i,c)=>{!i||!c||i.addEventListener("click",()=>{c.value="",c.dispatchEvent(new Event("input",{bubbles:!0})),c.focus()})};r(e.searchClearButton,e.searchBox),r(e.mobileSearchClearButton,e.mobileSearchBox),me(e.sortOptions,e.mobileSortOptions,"change",t),J(e.toggleClosedSourceSwitch,e.mobileClosedSourceSwitch,i=>{a.ui.showClosedSource=i,localStorage.setItem("showClosedSource",a.ui.showClosedSource),v(),L()}),J(e.partnersFilterCheckbox,e.mobilePartnersCheckbox,t),J(e.bookmarksFilterCheckbox,e.mobileBookmarksCheckbox,t),J(e.iconsFilterCheckbox,e.mobileIconsCheckbox,t),ie(e.tagFilterTrigger,e.tagFilterDropdown),ie(e.licenseFilterTrigger,e.licenseFilterDropdown),ie(e.languageFilterTrigger,e.languageFilterDropdown),ie(e.dynamicFilterTrigger,e.dynamicFilterDropdown),[e.tagFilterDropdown,e.licenseFilterDropdown,e.languageFilterDropdown,e.dynamicFilterDropdown].forEach(i=>{i.addEventListener("click",c=>{c.stopPropagation()})}),document.addEventListener("click",()=>{document.querySelectorAll(".custom-multiselect-dropdown.active").forEach(i=>{W(i)})}),e.toggleDetailsSwitch.addEventListener("change",()=>{a.ui.detailsVisible=e.toggleDetailsSwitch.checked,a.ui.detailsVisible?(document.body.classList.add("details-toggle-active"),document.querySelectorAll(".tile-slot").forEach(i=>{i.style.height=""}),document.querySelectorAll(".tile").forEach(i=>{i.style.minHeight=""}),document.querySelectorAll(".tile").forEach(i=>{i.classList.add("details-expanded");let c=i.querySelector(".details-container");c&&(c.style.display="flex");let l=i.querySelector(".tags-container");l&&(l.style.display="flex")})):(document.body.classList.remove("details-toggle-active"),document.querySelectorAll(".tile").forEach(i=>{i.classList.remove("tile-hovered","details-expanded");let c=i.querySelector(".details-container"),l=i.querySelector(".tags-container");Y()?(c&&(c.style.display="none"),l&&(l.style.display="none")):(c&&(c.style.display=""),l&&(l.style.display=""))}),ne())});let o=document.createElement("div");e.dataContainer.after(o);function n(){let i=a.io.currentBatch===0?0:$+(a.io.currentBatch-1)*G;!a.io.loading&&i<a.ui.filteredApps.length&&o.getBoundingClientRect().top<window.innerHeight+ce&&oe()}e.onBatchLoaded=n,new IntersectionObserver(i=>{i[0].isIntersecting&&n()},{rootMargin:`${ce}px`}).observe(o),document.addEventListener("keydown",i=>{let c=i.key==="/"&&!i.metaKey&&!i.ctrlKey&&!i.altKey,l=(i.metaKey||i.ctrlKey)&&i.key.toLowerCase()==="k";if(!c&&!l)return;let u=i.target,d=u&&(u.tagName==="INPUT"||u.tagName==="TEXTAREA"||u.isContentEditable);if(c&&d)return;i.preventDefault();let s=Y()&&e.mobileSearchBox?e.mobileSearchBox:e.searchBox;s&&(s.focus(),s.select())}),document.addEventListener("keydown",i=>{let c=document.activeElement;if(!c||c.tagName==="INPUT"||c.tagName==="TEXTAREA"||c.isContentEditable)return;let l=c.closest?.(".tile");if(!l||!e.dataContainer.contains(l)||l.classList.contains("tile-skeleton"))return;if(i.key==="b"||i.key==="B"){let p=l.querySelector(".bookmark-container");p&&(i.preventDefault(),p.click());return}if(!i.key.startsWith("Arrow"))return;let u=Array.from(e.dataContainer.querySelectorAll(".tile:not(.tile-skeleton)")),d=u.indexOf(l);if(d===-1)return;let s=null;if(i.key==="ArrowRight"?s=u[d+1]:i.key==="ArrowLeft"?s=u[d-1]:s=ht(l,u,i.key==="ArrowDown"?"down":"up"),!s)return;i.preventDefault();let m=s.querySelector(".project-name");m&&(m.focus(),s.scrollIntoView({block:"nearest"}))}),pt()}function ht(t,r,o){let n=t.getBoundingClientRect(),i=r.filter(d=>{if(d===t)return!1;let s=d.getBoundingClientRect();return o==="down"?s.top>n.top+1:s.top<n.top-1});if(i.length===0)return null;let c=i.map(d=>d.getBoundingClientRect().top),l=o==="down"?Math.min(...c):Math.max(...c);return i.filter(d=>Math.abs(d.getBoundingClientRect().top-l)<5).reduce((d,s)=>{if(d===null)return s;let m=Math.abs(s.getBoundingClientRect().left-n.left),p=Math.abs(d.getBoundingClientRect().left-n.left);return m<p?s:d},null)}function oe(){if(a.io.loading)return;a.io.loading=!0;let t=document.createDocumentFragment(),r=a.io.currentBatch===0?$:G,o=a.io.currentBatch===0?0:$+(a.io.currentBatch-1)*G,n=o+r,i=P();a.ui.filteredApps.slice(o,n).forEach(c=>{let l=Ct(c,i),u=document.createElement("div");u.className="tile-slot",u.appendChild(l),window.innerWidth>Te&&xt(u,l),t.appendChild(u)}),e.dataContainer.appendChild(t),a.io.currentBatch++,a.io.loading=!1,ne(),e.onBatchLoaded?.(),a.ui.filteredApps.length===0?e.noResultsContainer.classList.remove("hidden"):e.noResultsContainer.classList.add("hidden"),a.io.isInitialLoad||L()}function Ze(){e.dataContainer.innerHTML="",a.io.currentBatch=0}var gt=210,kt=175,Fe=14;function bt(){let t=e.dataContainer.clientWidth||window.innerWidth,r=Math.max(1,Math.floor((t+Fe)/(gt+Fe))),o=Math.ceil(window.innerHeight/(kt+Fe))+1;return Math.min($,r*o)}function ge(t){t==null&&(t=bt()),e.dataContainer.innerHTML="";let r=document.createDocumentFragment();for(let o=0;o<t;o++){let n=document.createElement("div");n.className="tile-slot",n.innerHTML=`<div class="tile tile-skeleton">
|
|
<div class="skeleton-icon"></div>
|
|
<div class="skeleton-line skeleton-line--name"></div>
|
|
<div class="skeleton-line"></div>
|
|
<div class="skeleton-line skeleton-line--desc-short"></div>
|
|
</div>`,r.appendChild(n)}e.dataContainer.appendChild(r)}function yt(){let t=Array.from(e.dataContainer.querySelectorAll(".project-name"));t.forEach(o=>o.classList.remove("name-multiline")),t.filter(o=>o.scrollHeight>parseFloat(getComputedStyle(o).lineHeight)*1.5).forEach(o=>o.classList.add("name-multiline"))}function ne(){document.body.classList.contains("details-toggle-active")||requestAnimationFrame(()=>{yt();let r=Array.from(e.dataContainer.querySelectorAll(".tile-slot")).map(u=>({slot:u,tile:u.querySelector(".tile")})),o=u=>{let d=new Map;u.forEach(({slot:s,tile:m})=>{let p=Math.round(s.offsetTop);d.has(p)||d.set(p,[]),d.get(p).push({slot:s,tile:m})}),d.forEach(s=>{let m=Math.max(...s.map(({slot:p})=>p.offsetHeight));s.forEach(({slot:p,tile:y})=>{p.style.height=m+"px",y&&(y.style.minHeight=m+"px")})})},n=({slot:u,tile:d})=>!!u.style.height||!!(d&&d.style.minHeight),i=r.filter(u=>!n(u));if(i.length===0){r.forEach(({slot:u,tile:d})=>{u.style.height="",d&&(d.style.minHeight="")}),requestAnimationFrame(()=>o(r));return}if(i.length===r.length){o(r);return}let c=new Set(i.map(({slot:u})=>Math.round(u.offsetTop))),l=r.filter(u=>n(u)&&c.has(Math.round(u.slot.offsetTop)));o([...i,...l])})}function Ke(){let t;window.addEventListener("resize",()=>{document.body.classList.contains("details-toggle-active")||(e.dataContainer.querySelectorAll(".tile-slot").forEach(r=>{r.style.height=""}),e.dataContainer.querySelectorAll(".tile").forEach(r=>{r.style.minHeight=""}),e.dataContainer.querySelectorAll(".project-name").forEach(r=>r.classList.remove("name-multiline")),clearTimeout(t),t=setTimeout(ne,Ae))})}function ve(t,r,o){let n=t[6],i=t[4];if(!n)return null;let c={"data-track-type":"apps-clicks","data-track-project-id":t[0]||"","data-track-link":"s","data-track-sponsor":r?1:0,"data-track-partner":o?1:0};if(n==="Closed")return F("span",{text:"Closed Source",className:"tag-chip closed-source-tag"});if(!i)return null;let l=F("a",{href:fe(i)+se,className:"tag-chip closed-source-tag source-link",target:"_blank",attrs:c}),u=parseInt(t[13])||0;return n==="GitHub"&&u>0?l.innerHTML=`<span>GitHub</span>${Ve}<span>${Ue(u)}</span>`:l.textContent=n||"Source",l}function Ct(t,r){let o=a.data.partners.sponsorRefs.has(t[2]),n=a.data.partners.partnerRefs.has(t[2]),i=a.data.partners.hosting.has(t[2]),c=document.createElement("div"),l=null;c.className="tile lazy-load",o&&c.classList.add("sponsor"),n&&c.classList.add("partner"),i&&c.classList.add("hosting-sponsor"),o&&c.appendChild(F("span",{text:"Sponsor",className:"sponsor-badge"}));let u=F("div",{className:"title-container"});if(t[9]!=="None"){let k="",x="project-icon";if(t[9]==="CDN")k=t[10];else{let R=t[9]==="Icons"?"https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/":"https://cdn.jsdelivr.net/gh/selfhst/cdn@main/directory/icons/apps/",I=(t[10]||t[2])+(t[11]==="Light"?"-light":"");k=R+I+".webp",x=t[11]==="Square"?"project-icon-square":"project-icon"}u.appendChild(F("img",{src:k,alt:(t[1]||"Unknown")+" Icon",className:x,width:48,height:48}))}else{let k=(t[1]||"U").charAt(0).toUpperCase();u.appendChild(F("div",{className:"icon-fallback",text:k}))}let d=a.data.partners.sponsorUrls.get(t[2]),s=a.data.partners.affiliateUrls.get(t[2]),m=s||d||fe(t[3]),p=m&&!m.includes("play.google.com")&&!s&&!d,y=t[0]||"";c.dataset.trackType="apps-clicks",c.dataset.trackProjectId=y,c.dataset.trackLink="w",c.dataset.trackSponsor=o?1:0,c.dataset.trackPartner=n?1:0;let h=F("a",{href:m+(p?se:""),className:"project-name",target:"_blank",attrs:{"data-track-type":"apps-clicks","data-track-project-id":y,"data-track-link":"w","data-track-sponsor":o?1:0,"data-track-partner":n?1:0}}),f=t[1]||"Unknown",S=document.createElement("span");if(S.textContent=f,h.appendChild(S),(()=>{h.style.whiteSpace="normal";let k=Ne-40,x=ae(f,Me,"500");n&&(x+=ee),x+=te,x>k?(x=ae(f,Re,"500")+(n?ee:0)+te,x>k?(x=ae(f,Oe,"500")+(n?ee:0)+te,x>k?h.classList.add("extremely-long-name"):h.classList.add("very-long-name")):h.classList.add("long-name")):h.style.whiteSpace=""})(),n){let k=document.createElement("span");k.className="partner-badge-inline",k.dataset.tooltip="Partner",k.innerHTML=`<svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.9 116.9">
|
|
<path d="M122.9,58.4l-13.7-15.6l2-20.5l-20.3-4.5L80.4,0l-19,8.2L42.5,0L31.9,17.9l-20.2,4.5l2,20.7L0,58.4L13.7,74
|
|
l-2,20.5L32,99.1l10.5,17.8l19.1-8.2l18.9,8.2L91,99l20.2-4.5l-2-20.7L122.9,58.4z M84.9,49.5L61.7,77.2c-2.6,2.8-7,3-9.9,0.4
|
|
c-4-3.7-9.8-9.1-13.9-12.6c-6.1-6.5,3.2-16.3,10-10.1c2.4,2.2,5.8,5.3,8.2,7.5l18.5-22.7C81.1,33,91.3,42.8,84.9,49.5z"/>
|
|
</svg>`,S.appendChild(k)}let g=document.createElement("button");g.type="button",g.className="bookmark-container",g.dataset.reference=t[2]||"";let b=document.createElement("span");b.className="bookmark-icon",b.innerHTML=`
|
|
<svg aria-hidden="true" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.25" d="M6 5a2 2 0 012-2h8a2 2 0 012 2v17l-6-3-6 3V5z"/>
|
|
</svg>
|
|
`,g.appendChild(b);let T=(r??P()).includes(t[2]);T&&b.classList.add("bookmarked"),g.setAttribute("aria-pressed",String(T)),g.setAttribute("aria-label",`Bookmark ${f}`),g.addEventListener("click",function(k){k.stopPropagation(),k.preventDefault(),Ce(t[2],g)});let U=F("div",{className:"name-row"});if(U.appendChild(h),U.appendChild(g),u.appendChild(U),c.appendChild(u),c.appendChild(F("div",{text:t[5],className:"project-description"})),a.ui.currentDirectory==="Software"){let k=ve(t,o,n);if(k){let x=F("div",{className:"source-chip-row"});x.appendChild(k),c.appendChild(x)}}let M=a.data.partners.hosting.get(t[2]);if(M){let k=F("a",{className:"partner-tagline-container",href:M.url,target:"_blank",dataset:{tooltip:M.linkType},attrs:{"data-track-type":"apps-clicks","data-track-project-id":y,"data-track-link":M.host.toLowerCase(),"data-track-sponsor":0,"data-track-partner":0}});k.appendChild(F("div",{text:M.tagline,className:"partner-tagline-text"})),k.appendChild(F("img",{src:M.icon,alt:M.host,className:"partner-tagline-image"})),c.appendChild(k)}if(a.ui.currentDirectory==="Software"){let k=F("div",{className:"tags-container"}),x=ve(t,o,n);x&&k.appendChild(x),(t[17]||[]).forEach(R=>{let I=a.data.tagsById.get(R)?.[1];if(!I)return;let O=F("a",{href:`https://selfh.st/apps/?tag=${encodeURIComponent(I)}`,text:I,className:"tag-chip"});k.appendChild(O)}),c.appendChild(k)}else if(a.ui.currentDirectory==="Companion"){let k=F("div",{className:"tags-container"});(t[23]||"").split(",").forEach(R=>{R.trim()&&k.appendChild(F("span",{text:R.trim(),className:"tag-chip"}))}),c.appendChild(k)}let K=t[6];if(K!=="Closed"){let k=function(I,O){let q=F("div",{className:"detail-row"});return q.appendChild(F("span",{text:I,className:"detail-label"})),q.appendChild(O),q};l=F("div",{className:"details-container"});let x=ve(t,o,n);x&&(l.appendChild(x),c.classList.add("has-detail-source"));let R=a.data.licensesData[parseInt(t[7])];if(R&&l.appendChild(k("License",F("span",{text:R,className:"detail-value"}))),K!=="Custom"){let I=a.data.languagesData[parseInt(t[8])];if(I&&l.appendChild(k("Language",F("span",{text:I,className:"detail-value"}))),t[15]){let O="";switch(t[16]){case"G":O="activity-green";break;case"Y":O="activity-yellow";break;case"R":O="activity-red";break}let q=F("span",{className:"detail-value"+(O?" "+O:"")});q.appendChild(document.createTextNode(t[15])),l.appendChild(k("Updated",q))}}c.appendChild(l)}if(a.ui.detailsVisible){c.classList.add("details-expanded");let k=c.querySelector(".details-container");k&&(k.style.display="flex");let x=c.querySelector(".tags-container");x&&(x.style.display="flex")}return c}function Y(){return window.innerWidth<=Ie}function St(){return document.body.classList.contains("details-toggle-active")}function xt(t,r){t.addEventListener("mouseenter",function(o){Y()||St()||r.classList.contains("details-expanded")||t.contains(o.relatedTarget)||r.classList.add("tile-hovered")}),t.addEventListener("mouseleave",function(o){t.contains(o.relatedTarget)||r.classList.remove("tile-hovered")})}function we(t,r,o,n,i,c,l=0,u=100){let d=l,s=u,m=!1,p=null;function y(g=!1){let b=u-l,D=(d-l)/b*100,T=(s-l)/b*100;o.style.left=`${D}%`,n.style.left=`${T}%`,r.style.left=`${D}%`,r.style.width=`${T-D}%`,i.textContent=N(d),c.textContent=N(s),g&&(a.ui.shareBookmarkIDs=null,v(),L())}function h(g){let b=t.getBoundingClientRect(),D=Math.max(0,Math.min(1,(g-b.left)/b.width));return Math.round(l+D*(u-l))}function f(g){let b=h(g.clientX),D=Math.abs(b-d),T=Math.abs(b-s);p=D<=T?"min":"max",m=!0,S(g),g.preventDefault()}function S(g){if(!m)return;let b=h(g.clientX);p==="min"?d=Math.min(b,s):s=Math.max(b,d),y()}function C(){m&&y(!0),m=!1,p=null}return t.addEventListener("mousedown",f),document.addEventListener("mousemove",S),document.addEventListener("mouseup",C),y(),{setRange:(g,b)=>{l=g,u=b,d=l,s=u,y(!1)},getValues:()=>({min:d,max:s}),getRange:()=>({min:l,max:u}),reset:()=>{d=l,s=u,y(!0)},destroy:()=>{t.removeEventListener("mousedown",f),document.removeEventListener("mousemove",S),document.removeEventListener("mouseup",C)}}}function ze(){let t=new URLSearchParams(window.location.search),r=t.get("search")||"",o=t.get("directory")||"Software";if(e.searchBox.value=r,e.mobileSearchBox&&(e.mobileSearchBox.value=r),e.mobileSortOptions){let n=e.sortOptions.value||"default";e.mobileSortOptions.value=n}(t.has("directory")||!a.ui.currentDirectory)&&Se(o||"Software"),a.io.isInitialLoad||v()}function je(t){a.ui.currentDirectory=t,a.ui.filteredApps=a.data.appDetailsData[t],v()}function et(t,r){let o=(t[1]||"").toLowerCase();if(o===r)return 5;if(o.startsWith(r))return 4;if(o.includes(r))return 3;if((t[2]||"").toLowerCase().includes(r))return 2;if(t[17]?.length){for(let n of t[17])if((a.data.tagsById.get(n)?.[1]||"").toLowerCase().includes(r))return 2}if(t[18]?.length){let n=a.ui.currentDirectory==="Companion"?a.data.companionSoftwareById:a.data.alternativesById;for(let i of t[18])if((n.get(i)?.[1]||"").toLowerCase().includes(r))return 2}return 1}function v(){let t=e.searchBox.value.toLowerCase(),r=a.ui.selectedDynamicFilters,o=a.ui.starSliderControl?a.ui.starSliderControl.getValues():{min:0,max:1/0},n=a.ui.forkSliderControl?a.ui.forkSliderControl.getValues():{min:0,max:1/0},i=e.sortOptions.value||"default",c=a.ui.starSliderControl?a.ui.starSliderControl.getRange():null,l=a.ui.forkSliderControl?a.ui.forkSliderControl.getRange():null,u=a.ui.starSliderControl&&o&&(o.min>0||o.max<c.max),d=a.ui.forkSliderControl&&n&&(n.min>0||n.max<l.max),s=t||a.ui.selectedTags.length>0||r.length>0||a.ui.selectedLicenses.length>0||a.ui.selectedLanguages.length>0||u||d||i!=="default"&&i!=="recent";if(a.io.currentBatch=0,Ze(),a.ui.filteredApps=[...a.data.appDetailsData[a.ui.currentDirectory]],a.ui.shareBookmarkIDs)a.ui.filteredApps=a.ui.filteredApps.filter(h=>a.ui.shareBookmarkIDs.includes(Number(h[0])));else{let h=P();a.ui.filteredApps=a.ui.filteredApps.filter(f=>{let S=!(e.partnersFilterCheckbox&&e.partnersFilterCheckbox.checked)||a.data.partners.partnerRefs.has(f[2]),C=!(e.bookmarksFilterCheckbox&&e.bookmarksFilterCheckbox.checked)||h.includes(f[2]),g=!(e.iconsFilterCheckbox&&e.iconsFilterCheckbox.checked)||f[12]&&f[12].toLowerCase().includes("y"),b=!t||f[1]?.toLowerCase().includes(t)||f[2]?.toLowerCase().includes(t)||f[5]?.toLowerCase().includes(t);if(!b&&t&&f[17]?.length&&(b=f[17].map(z=>a.data.tagsById.get(z)?.[1]?.toLowerCase()||"").some(z=>z.includes(t))),!b&&t&&f[18]?.length){let E=a.ui.currentDirectory==="Companion"?a.data.companionSoftwareById:a.data.alternativesById;b=f[18].map(j=>E.get(j)?.[1]?.toLowerCase()||"").some(j=>j.includes(t))}if(!b&&t){let E=a.data.partners.hosting.get(f[2]);E&&(b=E.host?.toLowerCase().includes(t)||E.tagline?.toLowerCase().includes(t))}let D=a.ui.selectedTags.length===0||a.ui.selectedTags.some(E=>(f[17]||[]).map(j=>a.data.tagsById.get(j)?.[1]).includes(E)),T=a.ui.currentDirectory==="Companion"?a.data.companionSoftwareById:a.data.alternativesById,U=(f[18]||[]).map(E=>T.get(E)?.[1]),M=r.length===0||r.some(E=>U.includes(E)),K=a.ui.showClosedSource||!["closed"].some(E=>f[6]?.toLowerCase().includes(E)),k=a.ui.selectedLicenses.length===0||f[7]!==void 0&&a.ui.selectedLicenses.includes(a.data.licensesData[parseInt(f[7])]),x=a.ui.selectedLanguages.length===0||f[8]!==void 0&&a.ui.selectedLanguages.includes(a.data.languagesData[parseInt(f[8])]),R=Number(f[13])||0,I=Number(f[14])||0,O=R>=o.min&&R<=o.max,q=I>=n.min&&I<=n.max;return S&&C&&g&&b&&D&&M&&K&&k&&x&&O&&q})}let m=a.data.originalOrderMaps[a.ui.currentDirectory];m||(m=new Map(a.data.appDetailsData[a.ui.currentDirectory].map((h,f)=>[h[0],f])),a.data.originalOrderMaps[a.ui.currentDirectory]=m);let p=(h,f)=>{switch(f){case"stars":return Number(h[13])||0;case"activity":return Number(h[19])||0;case"alphabetical":return h[1]||"";case"recent":return Number(h[20])||0;case"age-asc":return Number(h[21])||0;case"age-desc":return Number(h[22])||0;case"random":return 0;default:return m.get(h[0])}};if(i==="random")for(let h=a.ui.filteredApps.length-1;h>0;h--){let f=Math.floor(Math.random()*(h+1));[a.ui.filteredApps[h],a.ui.filteredApps[f]]=[a.ui.filteredApps[f],a.ui.filteredApps[h]]}let y=new Map;i==="default"&&!s&&a.ui.filteredApps.forEach(h=>{a.data.partners.sponsorRefs.has(h[2])&&y.set(h[2],Math.random())}),a.ui.filteredApps.sort((h,f)=>{if(t&&i==="default"){let g=et(f,t)-et(h,t);if(g!==0)return g}if(i==="default"&&!s){let g=a.data.partners.sponsorRefs.has(h[2]),b=a.data.partners.sponsorRefs.has(f[2]);if(g!==b)return g?-1:1;if(g&&b)return y.get(h[2])-y.get(f[2]);let D=a.data.partners.partnerRefs.has(h[2]),T=a.data.partners.partnerRefs.has(f[2]);if(D||T){let U=m.get(h[0])||0,M=m.get(f[0])||0;return D&&(U*=ue),T&&(M*=ue),U-M}}if(i==="age-asc"||i==="age-desc"){let g=h[6]?.toLowerCase().includes("closed"),b=f[6]?.toLowerCase().includes("closed");if(g&&!b)return 1;if(b&&!g)return-1}let S=p(h,i),C=p(f,i);if(i==="default"&&typeof S=="number"&&typeof C=="number"){let g=a.data.partners.partnerRefs.has(h[2]),b=a.data.partners.partnerRefs.has(f[2]);g&&(S*=de),b&&(C*=de)}return typeof S=="string"?S.localeCompare(C):i==="stars"||i==="activity"||i==="recent"?C-S:S-C}),oe(),re()}function le({values:t,optionsEl:r,trigger:o,mobileSelect:n,idPrefix:i,urlParam:c,stateKey:l,postChange:u}){if(!r)return;r.innerHTML="",a.ui[l]=[];let d=`${i}-all`,s=f=>`${i}-${f.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9-]/g,"")}`,m=new URLSearchParams(window.location.search).get(c);if(m){let S=m.split(",").map(C=>C.trim()).filter(C=>C).filter(C=>t.includes(C));S.length>0&&(a.ui[l]=S)}let p=document.createElement("div");p.className="custom-multiselect-option all-option",p.setAttribute("tabindex","-1"),p.setAttribute("role","option");let y=a.ui[l].length===0;p.setAttribute("aria-selected",String(y)),p.innerHTML=`
|
|
<input type="checkbox" id="${d}" ${y?"checked":""}>
|
|
<label for="${d}"><strong>All</strong></label>
|
|
`;let h=p.querySelector("input");h.addEventListener("change",f=>{f.target.checked&&(r.querySelectorAll(`input[type="checkbox"]:not(#${d})`).forEach(S=>{S.checked=!1,S.closest(".custom-multiselect-option")?.setAttribute("aria-selected","false")}),p.setAttribute("aria-selected","true"),a.ui[l]=[],B(o,a.ui[l]),v(),A(a.ui.currentDirectory))}),r.appendChild(p),t.forEach(f=>{let S=s(f),C=document.createElement("div");C.className="custom-multiselect-option",C.setAttribute("tabindex","-1"),C.setAttribute("role","option");let g=a.ui[l].includes(f);C.setAttribute("aria-selected",String(g)),C.innerHTML=`
|
|
<input type="checkbox" id="${S}" value="${f}" ${g?"checked":""}>
|
|
<label for="${S}">${f}</label>
|
|
`,C.querySelector("input").addEventListener("change",b=>{C.setAttribute("aria-selected",String(b.target.checked)),b.target.checked?(h.checked=!1,p.setAttribute("aria-selected","false"),a.ui[l].push(f)):(a.ui[l]=a.ui[l].filter(D=>D!==f),a.ui[l].length===0&&(h.checked=!0,p.setAttribute("aria-selected","true"))),B(o,a.ui[l]),u?.(),v(),A(a.ui.currentDirectory)}),r.appendChild(C)}),B(o,a.ui[l]),n&&(n.innerHTML='<option value="">All</option>',t.forEach(f=>n.appendChild(new Option(f,f))),a.ui[l].length===1&&(n.value=a.ui[l][0]))}function Ge(t,r){if(!t||t.length===0)return;let o=t.filter(n=>r?r==="Software"?n[2]===1:r==="Companion"?n[3]===1:!0:!0);le({values:o.map(n=>n[1]),optionsEl:e.tagFilterOptions,trigger:e.tagFilterTrigger,mobileSelect:e.mobileTagFilter,idPrefix:"tag",urlParam:"tag",stateKey:"selectedTags"})}async function Je(t){if(!e.dynamicFilterOptions)return;let r=[];t==="Software"?(e.dynamicFilterLabel.textContent="Alternatives",r=a.data.dynamicFilterData.map(o=>o[1])):t==="Companion"&&(e.dynamicFilterLabel.textContent="Software",await _e(),r=a.data.companionSoftwareData.map(o=>o[1])),le({values:r,optionsEl:e.dynamicFilterOptions,trigger:e.dynamicFilterTrigger,mobileSelect:e.mobileDynamicFilter,idPrefix:"dynamic",urlParam:t==="Companion"?"companion":"alternative",stateKey:"selectedDynamicFilters",postChange:()=>{a.ui.shareBookmarkIDs=null}}),e.mobileDynamicFilterLabel&&e.dynamicFilterLabel&&(e.mobileDynamicFilterLabel.textContent=e.dynamicFilterLabel.textContent)}function Le(t){if(!t)return;let r=[{text:"Default",value:"default"},{text:"Stars",value:"stars"},{text:"Activity",value:"activity"},{text:"Alphabetical",value:"alphabetical"},{text:"Recently Added",value:"recent"},{text:"Age (Ascending)",value:"age-asc"},{text:"Age (Descending)",value:"age-desc"},{text:"Random",value:"random"}];t.innerHTML="",r.forEach(o=>t.add(new Option(o.text,o.value))),t.value="default"}function ke(){!a.data.licensesData||a.data.licensesData.length===0||le({values:[...new Set(a.data.licensesData)].sort((t,r)=>t.localeCompare(r)),optionsEl:e.licenseFilterOptions,trigger:e.licenseFilterTrigger,mobileSelect:e.mobileLicenseFilter,idPrefix:"license",urlParam:"license",stateKey:"selectedLicenses"})}function be(){!a.data.languagesData||a.data.languagesData.length===0||le({values:[...new Set(a.data.languagesData)].sort((t,r)=>t.localeCompare(r)),optionsEl:e.languageFilterOptions,trigger:e.languageFilterTrigger,mobileSelect:e.mobileLanguageFilter,idPrefix:"language",urlParam:"language",stateKey:"selectedLanguages"})}function Xe(){a.ui.selectedLicenses=[],a.ui.selectedLanguages=[],e.licenseFilterOptions&&(e.licenseFilterOptions.querySelectorAll('input[type="checkbox"]').forEach(t=>{t.checked=t.id==="license-all"}),B(e.licenseFilterTrigger,a.ui.selectedLicenses)),e.languageFilterOptions&&(e.languageFilterOptions.querySelectorAll('input[type="checkbox"]').forEach(t=>{t.checked=t.id==="language-all"}),B(e.languageFilterTrigger,a.ui.selectedLanguages)),e.mobileLicenseFilter&&(e.mobileLicenseFilter.value=""),e.mobileLanguageFilter&&(e.mobileLanguageFilter.value="")}function B(t,r){if(!t)return;let o=t.querySelector(".custom-multiselect-text");o&&(r.length===0?o.textContent="All":r.length===1?o.textContent=r[0]:o.textContent=`${r.length} selected`)}function Ye(){if(!a.data.appDetailsData[a.ui.currentDirectory]||a.data.appDetailsData[a.ui.currentDirectory].length===0)return;let t=a.data.appDetailsData[a.ui.currentDirectory],r=t.map(c=>Number(c[13])||0).filter(c=>c>=0),o=t.map(c=>Number(c[14])||0).filter(c=>c>=0),n=Math.max(...r,1),i=Math.max(...o,1);a.ui.starSliderControl?a.ui.starSliderControl.setRange(0,n):a.ui.starSliderControl=we(e.starSlider,e.starFill,e.starThumbMin,e.starThumbMax,e.starMinValue,e.starMaxValue,0,n),a.ui.forkSliderControl?a.ui.forkSliderControl.setRange(0,i):a.ui.forkSliderControl=we(e.forkSlider,e.forkFill,e.forkThumbMin,e.forkThumbMax,e.forkMinValue,e.forkMaxValue,0,i)}async function Ft(){let t="https://selfh.st/apps/?bookmarks=",r="";a.ui.currentDirectory==="Software"?r="s":a.ui.currentDirectory==="Companion"&&(r="c");let o=P(),i=a.data.appDetailsData[a.ui.currentDirectory].filter(l=>o.includes(l[2])).map(l=>l[0]).slice(0,50);if(i.length<2)return _("Select 2 or more bookmarks to generate a share URL."),null;let c=t+r+i.join(",");try{let l=await fetch("https://selfh.st/apps/share/generate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({longUrl:c}),credentials:"include"});if(l.status===401||l.status===429){let d=await l.json();return _(d.error,{persistent:!0}),null}if(!l.ok)throw new Error("Failed to generate share URL");return(await l.json()).shortUrl}catch(l){return console.error("Error generating short URL:",l),null}}function vt(){e.mobileCategorySoftware&&(e.mobileCategorySoftware.checked=a.ui.currentDirectory==="Software"),e.mobileCategoryCompanion&&(e.mobileCategoryCompanion.checked=a.ui.currentDirectory==="Companion"),e.mobileClosedSourceSwitch&&(e.mobileClosedSourceSwitch.checked=a.ui.showClosedSource),e.mobilePartnersCheckbox&&e.partnersFilterCheckbox&&(e.mobilePartnersCheckbox.checked=e.partnersFilterCheckbox.checked),e.mobileBookmarksCheckbox&&e.bookmarksFilterCheckbox&&(e.mobileBookmarksCheckbox.checked=e.bookmarksFilterCheckbox.checked),e.mobileIconsCheckbox&&e.iconsFilterCheckbox&&(e.mobileIconsCheckbox.checked=e.iconsFilterCheckbox.checked),e.mobileDynamicFilter&&(e.mobileDynamicFilter.value=a.ui.selectedDynamicFilters.length===1?a.ui.selectedDynamicFilters[0]:""),e.mobileDynamicFilterLabel&&(e.mobileDynamicFilterLabel.textContent=e.dynamicFilterLabel?e.dynamicFilterLabel.textContent:"Alternatives"),e.mobileTagFilter&&(e.mobileTagFilter.value=a.ui.selectedTags.length===1?a.ui.selectedTags[0]:""),e.mobileLicenseFilter&&(e.mobileLicenseFilter.value=a.ui.selectedLicenses.length===1?a.ui.selectedLicenses[0]:""),e.mobileLanguageFilter&&(e.mobileLanguageFilter.value=a.ui.selectedLanguages.length===1?a.ui.selectedLanguages[0]:""),wt()}var Z=null;function wt(){e.mobileFilterOverlay&&(Z=document.activeElement,e.mobileFilterOverlay.classList.add("active"),e.mobileFilterOverlay.setAttribute("aria-hidden","false"),document.body.style.overflow="hidden",requestAnimationFrame(()=>e.mobileFilterClose?.focus()))}function Be(){e.mobileFilterOverlay&&(e.mobileFilterOverlay.classList.remove("active"),e.mobileFilterOverlay.setAttribute("aria-hidden","true"),document.body.style.overflow="",Z&&typeof Z.focus=="function"&&Z.focus(),Z=null)}function Lt(){document.querySelectorAll('input[name="m-category"]').forEach(r=>{r.addEventListener("change",function(){this.checked&&xe(this.value)})});let t=(r,o,n)=>{r&&r.addEventListener("change",()=>{a.ui[n]=r.value?[r.value]:[],B(o,a.ui[n]),a.ui.shareBookmarkIDs=null,v(),A(a.ui.currentDirectory)})};t(e.mobileTagFilter,e.tagFilterTrigger,"selectedTags"),t(e.mobileLicenseFilter,e.licenseFilterTrigger,"selectedLicenses"),t(e.mobileLanguageFilter,e.languageFilterTrigger,"selectedLanguages"),t(e.mobileDynamicFilter,e.dynamicFilterTrigger,"selectedDynamicFilters"),e.mobileClearFiltersButton&&e.mobileClearFiltersButton.addEventListener("click",X)}function tt(){document.getElementById("deleteBookmarksButton")?.addEventListener("click",()=>{localStorage.removeItem("bookmarks"),Q(),_("Bookmarks removed. Refresh to apply.")}),e.mobileFilterBtn&&(e.mobileFilterBtn.addEventListener("click",vt),Lt()),e.mobileFilterOverlay&&e.mobileFilterOverlay.addEventListener("click",t=>{t.target===e.mobileFilterOverlay&&Be()}),e.mobileFilterClose&&e.mobileFilterClose.addEventListener("click",Be),document.addEventListener("keydown",t=>{t.key==="Escape"&&e.mobileFilterOverlay?.classList.contains("active")&&Be()}),e.shareButton&&e.shareButton.addEventListener("click",async function(){let t=await Ft();t&&(e.shareButton.dataset.shareurl=t,navigator.clipboard.writeText(t).then(()=>{_("Share URL copied to clipboard. Limited to 50 bookmarks.")}).catch(()=>{_("Failed to copy share URL. Please try again.",{persistent:!0})}))})}function Bt(){let t=document.getElementById("toggleClosedSourceSwitch"),r=document.getElementById("m-toggleClosedSourceSwitch"),o=localStorage.getItem("showClosedSource");t&&o!==null&&(t.checked=o!=="false",r&&(r.checked=t.checked))}document.addEventListener("DOMContentLoaded",async()=>{if(document.querySelector(".main-layout")){Bt(),De(),a.ui.showClosedSource=e.toggleClosedSourceSwitch.checked,Qe(),Ke(),tt(),Q();try{let r=$e();if(r)await he(r,!0);else{let o=new URLSearchParams(window.location.search);await he(o.get("directory")||"Software",!1)}Le(e.sortOptions),Le(e.mobileSortOptions)}catch(r){console.error("Failed to initialize app:",r),e.dataContainer.innerHTML='<div class="error-message">Failed to load apps. Please try again.</div>'}}});})();
|