// theme preference function media_theme_pref() { document.documentElement.removeAttribute("class"); if ( window.matchMedia("(prefers-color-scheme: dark)").matches && (!window.localStorage.getItem("attobin:theme") || window.localStorage.getItem("attobin:theme") === "Auto") ) { document.documentElement.classList.add("dark"); document.getElementById("switch_light").classList.add("hidden"); document.getElementById("switch_dark").classList.remove("hidden"); } else if ( window.matchMedia("(prefers-color-scheme: light)").matches && (!window.localStorage.getItem("attobin:theme") || window.localStorage.getItem("attobin:theme") === "Auto") ) { document.documentElement.classList.remove("dark"); document.getElementById("switch_light").classList.remove("hidden"); document.getElementById("switch_dark").classList.add("hidden"); } else if (window.localStorage.getItem("attobin:theme")) { /* restore theme */ const current = window.localStorage.getItem("attobin:theme"); document.documentElement.className = current.toLowerCase(); if (current === "Light") { document.getElementById("switch_light").classList.remove("hidden"); document.getElementById("switch_dark").classList.add("hidden"); } else { document.getElementById("switch_light").classList.add("hidden"); document.getElementById("switch_dark").classList.remove("hidden"); } } } globalThis.temporary_set_theme = (theme) => { document.documentElement.className = theme.toLowerCase(); if (theme === "Light") { document.getElementById("switch_light").classList.remove("hidden"); document.getElementById("switch_dark").classList.add("hidden"); } else { document.getElementById("switch_light").classList.add("hidden"); document.getElementById("switch_dark").classList.remove("hidden"); } }; globalThis.set_theme = (theme) => { window.localStorage.setItem("attobin:theme", theme); document.documentElement.className = theme; media_theme_pref(); }; media_theme_pref(); // messages function get_cookie(key) { return (document.cookie.split(`${key}=`)[1] || "").split(";")[0]; } function check_message() { const element = document.getElementById("messages"); const message = get_cookie("Atto-Message"); const message_good = get_cookie("Atto-Message-Good") === "true"; if (message) { element.style.marginBottom = "1rem"; element.style.paddingLeft = "1rem"; element.innerHTML = `
  • ${message.replaceAll('"', "")}
  • `; } // clear cookies for (cookie of document.cookie.split(";")) { // biome-ignore lint/suspicious/noDocumentCookie: cookie store is barely supported document.cookie = `${cookie.split("=")[0]}=; expires=${new Date(0).toUTCString()}; path=/`; } } globalThis.show_message = (message, message_good = true) => { const element = document.getElementById("messages"); element.style.marginBottom = "1rem"; element.style.paddingLeft = "1rem"; element.innerHTML = `
  • ${message.replaceAll('"', "")}
  • `; }; check_message(); // editor globalThis.init_editor = ( name = "editor", mode = "markdown", element = "editor_tab", content_element = "editor_content", ) => { globalThis[name] = CodeMirror(document.getElementById(element), { value: (document.getElementById(content_element) || { innerHTML: "" }) .innerHTML, mode, lineWrapping: true, lineNumbers: false, autoCloseBrackets: true, autofocus: true, viewportMargin: Number.POSITIVE_INFINITY, inputStyle: "textarea", highlightFormatting: false, fencedCodeBlockHighlighting: false, xml: false, smartIndent: false, indentUnit: 4, tabSize: 4, indentWithTabs: false, placeholder: "", extraKeys: { Home: "goLineLeft", End: "goLineRight", Enter: (cm) => { cm.replaceSelection("\n"); }, Tab: "insertSoftTab", }, }); if (name === "editor") { window.addEventListener("beforeunload", (e) => { if (!globalThis.ALLOW_LEAVE) { e.preventDefault(); return null; } }); } }; globalThis.tab_editor = () => { document.getElementById("editor_tab").classList.remove("hidden"); document.getElementById("preview_tab").classList.add("hidden"); document.getElementById("metadata_tab").classList.add("hidden"); document.getElementById("editor_tab_button").classList.remove("camo"); document.getElementById("preview_tab_button").classList.add("camo"); document.getElementById("metadata_tab_button").classList.add("camo"); if (document.getElementById("metadata_css")) { document.getElementById("metadata_css").remove(); } }; globalThis.tab_preview = async () => { if ( !document .getElementById("preview_tab_button") .classList.contains("camo") ) { return; } // render const res = await ( await fetch("/api/v1/render", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ content: globalThis.editor.getValue(), metadata: globalThis.metadata_editor.getValue(), }), }) ).text(); document.getElementById("preview_tab").innerHTML = res; hljs.highlightAll(); // ... document.getElementById("editor_tab").classList.add("hidden"); document.getElementById("preview_tab").classList.remove("hidden"); document.getElementById("metadata_tab").classList.add("hidden"); document.getElementById("editor_tab_button").classList.add("camo"); document.getElementById("preview_tab_button").classList.remove("camo"); document.getElementById("metadata_tab_button").classList.add("camo"); }; globalThis.first_time_on_metadata_tab = true; globalThis.tab_metadata = () => { document.getElementById("editor_tab").classList.add("hidden"); document.getElementById("preview_tab").classList.add("hidden"); document.getElementById("metadata_tab").classList.remove("hidden"); document.getElementById("editor_tab_button").classList.add("camo"); document.getElementById("preview_tab_button").classList.add("camo"); document.getElementById("metadata_tab_button").classList.remove("camo"); if (globalThis.first_time_on_metadata_tab) { globalThis.metadata_editor.refresh(); } globalThis.first_time_on_metadata_tab = false; }; let exists_timeout = null; globalThis.check_exists_input = (e) => { if (exists_timeout) { clearTimeout(exists_timeout); } exists_timeout = setTimeout(async () => { if (e.target.value.length < 2 || e.target.value.length > 32) { e.target.setCustomValidity(""); e.target.removeAttribute("data-invalid"); e.target.reportValidity(); return; } const exists = ( await (await fetch(`/api/v1/entries/${e.target.value}`)).json() ).payload; console.log(exists); if (exists) { e.target.setCustomValidity("Slug is already in use"); e.target.setAttribute("data-invalid", "true"); } else { e.target.setCustomValidity(""); e.target.removeAttribute("data-invalid"); } e.target.reportValidity(); }, 1000); }; // components function close_dropdowns() { for (const dropdown of Array.from( document.querySelectorAll(".inner.open"), )) { dropdown.classList.remove("open"); } } globalThis.open_dropdown = (event) => { event.stopImmediatePropagation(); let target = event.target; while (!target.matches(".dropdown")) { target = target.parentElement; } // close all others close_dropdowns(); // open setTimeout(() => { for (const dropdown of Array.from(target.querySelectorAll(".inner"))) { // check y const box = target.getBoundingClientRect(); let parent = dropdown.parentElement; while (!parent.matches("html, .window")) { parent = parent.parentElement; } let parent_height = parent.getBoundingClientRect().y; if (parent.nodeName === "HTML") { parent_height = window.screen.height; } const scroll = window.scrollY; const height = parent_height; const y = box.y + scroll; if (y > height - scroll - 375) { dropdown.classList.add("top"); } else { dropdown.classList.remove("top"); } // open dropdown.classList.add("open"); if (dropdown.classList.contains("open")) { dropdown.removeAttribute("aria-hidden"); } else { dropdown.setAttribute("aria-hidden", "true"); } } }, 5); }; globalThis.init_dropdowns = (bind_to) => { for (const dropdown of Array.from(document.querySelectorAll(".inner"))) { dropdown.setAttribute("aria-hidden", "true"); } bind_to.addEventListener("click", (event) => { if ( event.target.matches(".dropdown") || event.target.matches("[exclude=dropdown]") ) { return; } for (const dropdown of Array.from( document.querySelectorAll(".inner.open"), )) { dropdown.classList.remove("open"); } }); }; globalThis.METADATA_CSS_ENABLED = true; globalThis.toggle_metadata_css = (e) => { e.target.classList.add("yellow"); METADATA_CSS_ENABLED = !METADATA_CSS_ENABLED; if (!METADATA_CSS_ENABLED) { media_theme_pref(); // user user theme document.getElementById("metadata_css").remove(); // remove css // reset colored text for (const element of Array.from( document.querySelectorAll(".color_block"), )) { element.removeAttribute("style"); element.classList.remove("color_block"); } // strikethrough auto theme since it's disabled document.getElementById("auto_theme").style.textDecoration = "line-through"; } else { window.location.reload(); } };