A music player that connects to your cloud/distributed storage.
at v4 130 lines 3.9 kB view raw
1import { html, render } from "lit-html"; 2import { keyed } from "lit-html/directives/keyed.js"; 3import { marked } from "marked"; 4import { unsafeHTML } from "lit-html/directives/unsafe-html.js"; 5 6import * as Output from "~/common/output.js"; 7import foundation from "~/common/facets/foundation.js"; 8import { effect } from "~/common/signal.js"; 9import { nothing } from "~/common/element.js"; 10 11//////////////////////////////////////////// 12// YOUR COLLECTION 13//////////////////////////////////////////// 14 15/** @type {HTMLElement | null} */ 16const listEl = document.querySelector("#list"); 17if (!listEl) throw new Error("List element not found"); 18 19const output = foundation.orchestrator.output(); 20 21listEl.innerHTML = ""; 22 23effect(() => { 24 const col = output.facets.collection().sort((a, b) => { 25 return a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase()); 26 }); 27 28 const state = output.facets.state(); 29 30 const h = col.length && state === "loaded" 31 ? html` 32 <ul class="grid" style="margin: 0"> 33 ${col.map((c, index) => 34 keyed( 35 c.id, 36 html` 37 <li class="grid-item"> 38 <div class="grid-item__contents"> 39 <div> 40 <a 41 href="facets/l/?id=${c 42 .id}" 43 style="display: inline-block; padding: var(--space-3xs) 0" 44 > 45 ${c.name} 46 </a> 47 </div> 48 <div class="list-description"> 49 <div> 50 ${c.description?.trim().length 51 ? unsafeHTML( 52 marked.parse(c.description, { async: false }), 53 ) 54 : nothing} 55 </div> 56 <div> 57 ${c.uri && !c.html 58 ? html` 59 <span class="with-icon"> 60 <i class="ph-fill ph-binoculars"></i> 61 <span>Tracking the original <a href="${c 62 .uri}">URI</a></span> 63 </span> 64 ` 65 : html` 66 <span class="with-icon"> 67 <i class="ph-fill ph-code-simple"></i> 68 <span>Custom code</span> 69 </span> 70 `} 71 </div> 72 </div> 73 </div> 74 75 <div class="grid-item__menu"> 76 <a 77 class="button button--transparent" 78 title="Edit" 79 href="facets/build/?id=${encodeURIComponent(c.id)}" 80 > 81 <i class="ph-fill ph-code-block"></i> 82 </a> 83 <hr /> 84 <button 85 class="button--transparent" 86 title="Delete" 87 @click="${deleteFacet({ id: c.id })}" 88 > 89 <i class="ph-fill ph-skull"></i> 90 </button> 91 </div> 92 </li> 93 `, 94 ) 95 )} 96 </ul> 97 ` 98 : state === "loaded" 99 ? emptyFacetsList 100 : html` 101 <div class="with-icon"> 102 <i class="ph-bold ph-spinner-gap"></i> 103 Loading items 104 </div> 105 `; 106 107 render(h, listEl); 108}); 109 110const emptyFacetsList = html` 111 <div> 112 <i class="ph-fill ph-info"></i> You have not saved any facets yet. 113 </div> 114`; 115 116/** 117 * @param {{ id: string }} _ 118 */ 119function deleteFacet({ id }) { 120 return async () => { 121 const c = confirm("Are you sure you want to delete this facet?"); 122 if (!c) return; 123 124 await Output.waitUntilLoaded(output.facets); 125 126 output.facets.save( 127 output.facets.collection().filter((c) => !(c.id === id)), 128 ); 129 }; 130}