A music player that connects to your cloud/distributed storage.
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}