import { html, render } from "lit-html"; import { classMap } from "lit-html/directives/class-map.js"; import { keyed } from "lit-html/directives/keyed.js"; import { marked } from "marked"; import { unsafeHTML } from "lit-html/directives/unsafe-html.js"; import * as FacetCategory from "~/common/facets/category.js"; import { batch, effect, signal } from "~/common/signal.js"; import { nothing } from "~/common/element.js"; import { deleteFacet, toggleFacetEnabled, toggleFacetFavourite } from "./crud.js"; import { output } from "./output.js"; import { openAddFromURIModal } from "./from-uri.js"; // Signals const FILTER_STORAGE_KEY = "diffuse/dashboard/filter"; const storedFilter = localStorage.getItem(FILTER_STORAGE_KEY); const activeFilter = signal( storedFilter === "prelude" || storedFilter === "interface" || storedFilter === "base" ? storedFilter : "all", ); effect(() => { localStorage.setItem(FILTER_STORAGE_KEY, activeFilter.get()); }); const UNFAVOURITE_COLLAPSED_KEY = "diffuse/dashboard/unfavourite-collapsed"; const unfavouriteCollapsed = signal( localStorage.getItem(UNFAVOURITE_COLLAPSED_KEY) === "true", ); effect(() => { localStorage.setItem( UNFAVOURITE_COLLAPSED_KEY, String(unfavouriteCollapsed.get()), ); }); /** @param {string} filter */ function setFilter(filter) { const url = new URL(location.href); url.searchParams.delete("filter"); history.replaceState(null, "", url); batch(() => { activeFilter.set(filter); unfavouriteCollapsed.set(false); }); } /** * @import OutputOrchestrator from "~/components/orchestrator/output/element.js"; * @import {Facet} from "~/definitions/types.d.ts"; */ const emptyFacetsList = () => html`

You haven't saved anything yet. Add a facet by browsing the featured ones or any of the other categories. You can click the toggle to quickly add or remove from your collection.

`; //////////////////////////////////////////// // LIST //////////////////////////////////////////// /** @type {() => void | undefined} */ let stopMonitor; /** */ export async function renderList() { if (stopMonitor) stopMonitor(); activeFilter.set((() => { const param = new URL(location.href).searchParams.get("filter"); if ( param === "prelude" || param === "interface" || param === "base" || param === "all" ) return param; const stored = localStorage.getItem(FILTER_STORAGE_KEY); return stored === "prelude" || stored === "interface" || stored === "base" ? stored : "all"; })()); /** @type {HTMLElement | null} */ const listEl = document.querySelector("#list"); if (!listEl) throw new Error("List element not found"); if (listEl.getAttribute("data-rendered") === "f") { listEl.innerHTML = ""; listEl.removeAttribute("data-rendered"); } const out = await output(); stopMonitor = effect(() => { _renderList(out, listEl); }); } /** * @param {OutputOrchestrator} output * @param {HTMLElement} listEl */ function _renderList(output, listEl) { const facetsCol = output.facets.collection(); if (facetsCol.state !== "loaded") { const loading = html`
Loading your software
`; render(loading, listEl); return; } const filter = activeFilter.get(); /** @param {Facet} a @param {Facet} b */ const sortByName = (a, b) => a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase()) || a.id.localeCompare(b.id); const filtered = facetsCol.state === "loaded" ? [...facetsCol.data].filter((c) => filter === "base" ? !!c.tags?.includes("base") : (filter === "all" || (filter === "prelude" ? c.kind === "prelude" : c.kind !== "prelude")) && !c.tags?.includes("base") ) : []; const favouriteCol = filtered.filter((c) => c.favourite).sort(sortByName); const unfavouriteCol = filtered.filter((c) => !c.favourite).sort(sortByName); const col = favouriteCol.concat(unfavouriteCol); const selected = output.selected(); const outputLabel = selected?.label ?? selected?.getAttribute?.("label") ?? "Local storage"; const filterBar = html`
Filter by
Userdata from ${outputLabel}
`; /** @param {Facet[]} items */ const renderItems = (items) => items.map((c) => { const color = FacetCategory.color(c); const title = c.kind === "prelude" ? html` ${c.name} ` : html` ${c.name} `; return keyed( c.id, html`
  • ${title}
    ${c.description?.trim().length ? unsafeHTML( marked.parse(c.description, { async: false }), ) : nothing}
    ${c.uri && !c.resources ? html` Tracking the original URI ` : html` Custom code `}

  • `, ); }); const collapsed = unfavouriteCollapsed.get() && favouriteCol.length > 0; const h = col.length || filter !== "all" ? html` ${filterBar} ${favouriteCol.length ? html` ` : nothing} ${favouriteCol.length && unfavouriteCol.length ? html`

    ` : nothing} ${unfavouriteCol.length && !collapsed ? html` ` : nothing} ` : html` ${filterBar} ${emptyFacetsList()} `; render(h, listEl); setTimeout(() => { /** @type {HTMLElement | null} */ const l = listEl.querySelector(".grid-filter--label-output"); /** @type {HTMLElement | null} */ const o = listEl.querySelector(".grid-filter--output"); if (o && l) { l.style.opacity = "0.4"; o.style.opacity = "1"; } }, 250); }