diff --git a/airlock/templates/file_browser/index.html b/airlock/templates/file_browser/index.html index 99abe8a8..ab118c22 100644 --- a/airlock/templates/file_browser/index.html +++ b/airlock/templates/file_browser/index.html @@ -39,4 +39,5 @@ {% django_htmx_script %} + {% vite_asset "assets/src/scripts/resizer.js" %} {% endblock %} diff --git a/assets/src/scripts/resizer.js b/assets/src/scripts/resizer.js new file mode 100644 index 00000000..a4ef7349 --- /dev/null +++ b/assets/src/scripts/resizer.js @@ -0,0 +1,81 @@ +// Magic number for resizing +const MAGIC_PIXELS = 8; + +/** + * Debounce a function to slow down how frequently it runs. + * + * @param {number} ms - Time to wait before running the function + * @param {function} fn - Function to run when being debounced + * @returns {function} + */ +function debouncer(ms, fn) { + let timer; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(fn.bind(fn, args), ms); + }; +} + +/** + * Set the content height for either iframes, or workspace/request content, + * so that it fills the available space. + */ +function setContentHeight() { + const iframe = document.querySelector("iframe"); + if (iframe) { + const iframeTop = iframe.getBoundingClientRect().top; + iframe.style.height = `${window.innerHeight - iframeTop - MAGIC_PIXELS}px`; + } + + const selectedContent = document.getElementById("selected-contents"); + if (selectedContent) { + const contentTop = selectedContent.getBoundingClientRect().top; + selectedContent.style.height = `${window.innerHeight - contentTop - MAGIC_PIXELS}px`; + selectedContent.classList.add("overflow-auto"); + } +} + +/** + * Set the height of the tree container to fill the available space. + */ +function setTreeHeight() { + const iframe = document.getElementById("tree-container"); + if (iframe) { + const iframeTop = iframe.getBoundingClientRect().top; + iframe.style.height = `${window.innerHeight - iframeTop - MAGIC_PIXELS}px`; + } +} + +/** + * On page load, add and remove the relevant styling classes, so that the + * content can fill the page. + */ +document.documentElement.classList.remove("min-h-screen"); +document.documentElement.classList.add("h-screen"); + +document.body.classList.remove("min-h-screen"); +document.body.classList.add("h-screen"); + +document.querySelector("main")?.classList.add("overflow-hidden"); + +/** + * On browser resize, change the height of the content and file tree. + * + * Use the debouncer function to make sure this only runs when a user stops + * dragging the window size. + */ +const ro = new ResizeObserver( + debouncer(100, () => { + setContentHeight(); + setTreeHeight(); + }), +); + +ro.observe(document.documentElement); + +/** + * When the user selects a file from the tree, HTMX replaces the content. + * Listen for this change, and reset the content height after the file content + * has been loaded. + */ +document.body.addEventListener("htmx:afterSettle", () => setContentHeight()); diff --git a/vite.config.js b/vite.config.js index 96b2d6bb..ec1e4957 100644 --- a/vite.config.js +++ b/vite.config.js @@ -8,6 +8,7 @@ export default defineConfig({ rollupOptions: { input: { main: "assets/src/scripts/main.js", + resizer: "assets/src/scripts/resizer.js", }, }, },