import { basicSetup, EditorView } from "codemirror";
import { css as langCss } from "@codemirror/lang-css";
import { html as langHtml } from "@codemirror/lang-html";
import { javascript as langJs } from "@codemirror/lang-javascript";
import { autocompletion } from "@codemirror/autocomplete";
import * as TID from "@atcute/tid";
import * as CID from "~/common/cid.js";
import * as Output from "~/common/output.js";
import foundation from "~/common/facets/foundation.js";
import { facetFromURI } from "~/common/facets/utils.js";
import { loadURI } from "~/common/loader.js";
import { signal } from "~/common/signal.js";
/**
* @import {Facet} from "~/definitions/types.d.ts"
*/
////////////////////////////////////////////
// BUILD
////////////////////////////////////////////
const output = foundation.orchestrator.output();
const $editingFacet = signal(/** @type {Facet | null} */ (null));
// Code editor
const editorContainer = document.body.querySelector("#html-input-container");
if (!editorContainer) throw new Error("Editor container not found");
const editor = new EditorView({
parent: editorContainer,
doc: `
Waiting on tracks & queue to load ...
`.trim(),
extensions: [
basicSetup,
langHtml(),
langCss(),
langJs(),
autocompletion(),
],
});
// Form submit
document.querySelector("#build-form")?.addEventListener(
"submit",
onBuildSubmit,
);
/**
* @param {Event} event
*/
async function onBuildSubmit(event) {
event.preventDefault();
const nameEl = /** @type {HTMLInputElement | null} */ (document.querySelector(
"#name-input",
));
const descriptionEl = /** @type {HTMLTextAreaElement | null} */ (
document.querySelector("#description-input")
);
const html = editor.state.doc.toString();
const cid = await CID.create(0x55, new TextEncoder().encode(html));
const name = nameEl?.value ?? "nameless";
const description = descriptionEl?.value ?? "";
/** @type {Facet} */
const facet = $editingFacet.value
? {
...$editingFacet.value,
cid,
description,
html,
name,
}
: {
$type: "sh.diffuse.output.facet",
id: TID.now(),
cid,
description,
html,
name,
};
switch (/** @type {any} */ (event).submitter.name) {
case "save":
await saveFacet(facet);
break;
case "save+open":
await saveFacet(facet);
globalThis.open(`./facets/l/?id=${facet.id}`, "blank");
break;
}
}
/**
* @param {Facet} ogFacet
*/
async function editFacet(ogFacet) {
const facet = { ...ogFacet };
const nameEl = /** @type {HTMLInputElement | null} */ (document.querySelector(
"#name-input",
));
const descriptionEl = /** @type {HTMLTextAreaElement | null} */ (
document.querySelector("#description-input")
);
if (!nameEl) return;
// Scroll to builder
document.querySelector("#build")?.scrollIntoView();
// Make sure HTML is loaded
if (!facet.html && facet.uri) {
const html = await loadURI(facet.uri);
const cid = await CID.create(0x55, new TextEncoder().encode(html));
facet.html = html;
facet.cid = cid;
}
$editingFacet.value = facet;
nameEl.value = facet.name;
if (descriptionEl) {
descriptionEl.value = facet.description ?? "";
}
editor.dispatch({
changes: { from: 0, to: editor.state.doc.length, insert: facet.html },
});
}
/**
* @param {Facet} facet
*/
async function saveFacet(facet) {
await Output.waitUntilLoaded(output.facets);
const col = output.facets.collection();
const colWithoutId = col.filter((c) => c.id !== facet.id);
await output.facets.save([...colWithoutId, {
...facet,
updatedAt: new Date().toISOString(),
}]);
}
////////////////////////////////////////////
// SAVE & FORK
////////////////////////////////////////////
document.body.addEventListener(
"click",
/**
* @param {MouseEvent} event
*/
async (event) => {
const target = /** @type {HTMLElement} */ (event.target);
const rel = target.getAttribute("rel");
if (!rel) return;
const uri = target.closest("li")?.getAttribute("data-uri");
if (!uri) return;
const name = target.closest("li")?.getAttribute("data-name");
if (!name) return;
switch (rel) {
case "edit": {
const facet = await facetFromURI({ name, uri }, { fetchHTML: true });
editFacet(facet);
document.querySelector("#build")?.scrollIntoView();
break;
}
}
},
);
////////////////////////////////////////////
// 🚀
////////////////////////////////////////////
await Output.waitUntilLoaded(output.facets);
// Load facet from url
const idParam = new URLSearchParams(location.search).get("id");
if (idParam) {
const facet = output.facets.collection().find((f) => f.id === idParam);
if (facet) await editFacet(facet);
}