From ad40f7fb0ca9cf79b9000e6cffee2b8ba37959cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniele=20Vigan=C3=B2?= Date: Sun, 18 Jan 2026 23:28:06 +0100 Subject: [PATCH] chore: add Makefile for frontend asset minification - Add comprehensive Makefile with targets for JS and CSS minification - Implements instructions from ram/portal/static/js/src/README.md - Provides targets: install, minify, minify-js, minify-css, clean, watch - Fix main.min.js to only include theme_selector.js and tabs_selector.js - Remove validators.js from minified output per README instructions --- Makefile | 70 ++++++++++++++++++++++++++++++++ ram/portal/static/js/main.min.js | 2 +- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c4f8771 --- /dev/null +++ b/Makefile @@ -0,0 +1,70 @@ +# Makefile for Django RAM project +# Handles frontend asset minification and common development tasks + +.PHONY: help minify minify-js minify-css clean install test + +# Directories +JS_SRC_DIR = ram/portal/static/js/src +JS_OUT_DIR = ram/portal/static/js +CSS_SRC_DIR = ram/portal/static/css/src +CSS_OUT_DIR = ram/portal/static/css + +# Source files +JS_SOURCES = $(JS_SRC_DIR)/theme_selector.js $(JS_SRC_DIR)/tabs_selector.js +CSS_SOURCES = $(CSS_SRC_DIR)/main.css + +# Output files +JS_OUTPUT = $(JS_OUT_DIR)/main.min.js +CSS_OUTPUT = $(CSS_OUT_DIR)/main.min.css + +# Default target +help: + @echo "Django RAM - Available Make targets:" + @echo "" + @echo " make install - Install npm dependencies (terser, clean-css-cli)" + @echo " make minify - Minify both JS and CSS files" + @echo " make minify-js - Minify JavaScript files only" + @echo " make minify-css - Minify CSS files only" + @echo " make clean - Remove minified files" + @echo " make help - Show this help message" + @echo "" + +# Install npm dependencies +install: + @echo "Installing npm dependencies..." + npm install + @echo "Done! terser and clean-css-cli installed." + +# Minify both JS and CSS +minify: minify-js minify-css + +# Minify JavaScript +minify-js: $(JS_OUTPUT) + +$(JS_OUTPUT): $(JS_SOURCES) + @echo "Minifying JavaScript..." + npx terser $(JS_SOURCES) -c -m -o $(JS_OUTPUT) + @echo "Created: $(JS_OUTPUT)" + +# Minify CSS +minify-css: $(CSS_OUTPUT) + +$(CSS_OUTPUT): $(CSS_SOURCES) + @echo "Minifying CSS..." + npx cleancss -o $(CSS_OUTPUT) $(CSS_SOURCES) + @echo "Created: $(CSS_OUTPUT)" + +# Clean minified files +clean: + @echo "Removing minified files..." + rm -f $(JS_OUTPUT) $(CSS_OUTPUT) + @echo "Clean complete." + +# Watch for changes (requires inotify-tools on Linux) +watch: + @echo "Watching for file changes..." + @echo "Press Ctrl+C to stop" + @while true; do \ + inotifywait -e modify,create $(JS_SRC_DIR)/*.js $(CSS_SRC_DIR)/*.css 2>/dev/null && \ + make minify; \ + done || echo "Note: install inotify-tools for file watching support" diff --git a/ram/portal/static/js/main.min.js b/ram/portal/static/js/main.min.js index 83d54c0..e019b98 100644 --- a/ram/portal/static/js/main.min.js +++ b/ram/portal/static/js/main.min.js @@ -3,4 +3,4 @@ * Copyright 2011-2023 The Bootstrap Authors * Licensed under the Creative Commons Attribution 3.0 Unported License. */ -(()=>{"use strict";const e=()=>localStorage.getItem("theme"),t=()=>{const t=e();return t||(window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light")},a=e=>{"auto"===e&&window.matchMedia("(prefers-color-scheme: dark)").matches?document.documentElement.setAttribute("data-bs-theme","dark"):document.documentElement.setAttribute("data-bs-theme",e)};a(t());const r=(e,t=!1)=>{const a=document.querySelector("#bd-theme");if(!a)return;const r=document.querySelector(".theme-icon-active i"),o=document.querySelector(`[data-bs-theme-value="${e}"]`),s=o.querySelector(".theme-icon i").getAttribute("class");document.querySelectorAll("[data-bs-theme-value]").forEach(e=>{e.classList.remove("active"),e.setAttribute("aria-pressed","false")}),o.classList.add("active"),o.setAttribute("aria-pressed","true"),r.setAttribute("class",s),t&&a.focus()};window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{const r=e();"light"!==r&&"dark"!==r&&a(t())}),window.addEventListener("DOMContentLoaded",()=>{r(t()),document.querySelectorAll("[data-bs-theme-value]").forEach(e=>{e.addEventListener("click",()=>{const t=e.getAttribute("data-bs-theme-value");(e=>{localStorage.setItem("theme",e)})(t),a(t),r(t,!0)})})})})(),document.addEventListener("DOMContentLoaded",function(){"use strict";const e=document.getElementById("tabSelector"),t=window.location.hash.substring(1);if(t){const a=`#nav-${t}`,r=document.querySelector(`[data-bs-target="${a}"]`);r&&(bootstrap.Tab.getOrCreateInstance(r).show(),e.value=a)}document.querySelectorAll('button[data-bs-toggle="tab"]').forEach(e=>{e.addEventListener("shown.bs.tab",e=>{const t=e.target.getAttribute("data-bs-target").replace("nav-","");history.replaceState(null,null,t)})}),e&&(e.addEventListener("change",function(){const e=this.value,t=document.querySelector(`[data-bs-target="${e}"]`);if(t){bootstrap.Tab.getOrCreateInstance(t).show()}}),document.querySelectorAll('[data-bs-toggle="tab"]').forEach(t=>{t.addEventListener("shown.bs.tab",t=>{const a=t.target.getAttribute("data-bs-target");e.value=a})}))}),document.addEventListener("DOMContentLoaded",function(){"use strict";const e=document.querySelectorAll(".needs-validation");Array.from(e).forEach(e=>{e.addEventListener("submit",t=>{e.checkValidity()||(t.preventDefault(),t.stopPropagation()),e.classList.add("was-validated")},!1)})}); \ No newline at end of file +(()=>{"use strict";const e=()=>localStorage.getItem("theme"),t=()=>{const t=e();return t||(window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light")},a=e=>{"auto"===e&&window.matchMedia("(prefers-color-scheme: dark)").matches?document.documentElement.setAttribute("data-bs-theme","dark"):document.documentElement.setAttribute("data-bs-theme",e)};a(t());const r=(e,t=!1)=>{const a=document.querySelector("#bd-theme");if(!a)return;const r=document.querySelector(".theme-icon-active i"),o=document.querySelector(`[data-bs-theme-value="${e}"]`),s=o.querySelector(".theme-icon i").getAttribute("class");document.querySelectorAll("[data-bs-theme-value]").forEach(e=>{e.classList.remove("active"),e.setAttribute("aria-pressed","false")}),o.classList.add("active"),o.setAttribute("aria-pressed","true"),r.setAttribute("class",s),t&&a.focus()};window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{const r=e();"light"!==r&&"dark"!==r&&a(t())}),window.addEventListener("DOMContentLoaded",()=>{r(t()),document.querySelectorAll("[data-bs-theme-value]").forEach(e=>{e.addEventListener("click",()=>{const t=e.getAttribute("data-bs-theme-value");(e=>{localStorage.setItem("theme",e)})(t),a(t),r(t,!0)})})})})(),document.addEventListener("DOMContentLoaded",function(){"use strict";const e=document.getElementById("tabSelector"),t=window.location.hash.substring(1);if(t){const a=`#nav-${t}`,r=document.querySelector(`[data-bs-target="${a}"]`);r&&(bootstrap.Tab.getOrCreateInstance(r).show(),e.value=a)}document.querySelectorAll('button[data-bs-toggle="tab"]').forEach(e=>{e.addEventListener("shown.bs.tab",e=>{const t=e.target.getAttribute("data-bs-target").replace("nav-","");history.replaceState(null,null,t)})}),e&&(e.addEventListener("change",function(){const e=this.value,t=document.querySelector(`[data-bs-target="${e}"]`);if(t){bootstrap.Tab.getOrCreateInstance(t).show()}}),document.querySelectorAll('[data-bs-toggle="tab"]').forEach(t=>{t.addEventListener("shown.bs.tab",t=>{const a=t.target.getAttribute("data-bs-target");e.value=a})}))}); \ No newline at end of file