From 279f40486b36c8701906080d547dcec0b9cfac3e Mon Sep 17 00:00:00 2001 From: Daniel Legt Date: Fri, 27 Feb 2026 12:13:52 +0200 Subject: [PATCH] Eh --- examples/generic.html | 5 +++- js/y2k-alert.js | 14 ++++++++- package.json | 7 +++++ scripts/build.js | 57 ++++++++++++++++++++--------------- scripts/watch.js | 69 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 25 deletions(-) create mode 100644 scripts/watch.js diff --git a/examples/generic.html b/examples/generic.html index 1a27404..b45ae82 100644 --- a/examples/generic.html +++ b/examples/generic.html @@ -33,7 +33,10 @@ var alertInstance = new y2kAlert( "Storage Warning", Y2K.TYPE_WARNING, - "Disk space is running low." + "Disk space is running low.", + { + closeOnBackdropClick: true + } ); alertInstance.addEventListener("submit", function (event) { diff --git a/js/y2k-alert.js b/js/y2k-alert.js index 97782cc..8c445b2 100644 --- a/js/y2k-alert.js +++ b/js/y2k-alert.js @@ -10,7 +10,9 @@ this.title = title || "Alert"; this.type = type || Y2K.TYPE_INFO; this.message = message || ""; - this.options = options || {}; + this.options = Object.assign({ + closeOnBackdropClick: false + }, options || {}); this.isVisible = false; this.inputElement = null; this.overlayElement = null; @@ -101,6 +103,16 @@ self.submit(); }); + this.overlayElement.addEventListener("click", function (event) { + if (!self.options.closeOnBackdropClick) { + return; + } + + if (event.target === self.overlayElement) { + self.close("backdrop"); + } + }); + if (this.inputElement) { this.inputElement.addEventListener("keydown", function (event) { if (event.key === "Enter") { diff --git a/package.json b/package.json index a339048..9212698 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,13 @@ "style": "dist/y2k-alerts.css", "scripts": { "build": "node scripts/build.js", + "watch": "node scripts/watch.js", "test": "npm run build" + }, + "devDependencies": { + "browser-sync": "^3.0.3", + "chokidar": "^3.6.0", + "clean-css": "^5.3.3", + "terser": "^5.31.2" } } diff --git a/scripts/build.js b/scripts/build.js index 5ad8d9d..d446e49 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,5 +1,7 @@ const fs = require("fs"); const path = require("path"); +const CleanCSS = require("clean-css"); +const { minify } = require("terser"); const ROOT_DIR = path.resolve(__dirname, ".."); const DIST_DIR = path.join(ROOT_DIR, "dist"); @@ -20,24 +22,8 @@ function readFiles(folder, files) { .join("\n\n"); } -function minifyCss(css) { - return css - .replace(/\/\*[\s\S]*?\*\//g, "") - .replace(/\s+/g, " ") - .replace(/\s*([{}:;,])\s*/g, "$1") - .replace(/;}/g, "}") - .trim(); -} - -function minifyJs(js) { - return js - .replace(/\/\*[\s\S]*?\*\//g, "") - .replace(/^\s*\/\/.*$/gm, "") - .replace(/\s+/g, " ") - .trim(); -} - function buildCss() { + const cssMinifier = new CleanCSS({ level: 2 }); const baseCss = readFiles(BASE_CSS_DIR, BASE_CSS_FILES); const themeFolders = fs .readdirSync(THEMES_DIR, { withFileTypes: true }) @@ -57,9 +43,14 @@ function buildCss() { const distFile = path.join(DIST_DIR, `y2k-alerts-${themeName}.css`); const distMinFile = path.join(DIST_DIR, `y2k-alerts-${themeName}.min.css`); + const minified = cssMinifier.minify(output); + + if (minified.errors.length > 0) { + throw new Error(`CSS minification failed for ${themeName}: ${minified.errors.join(", ")}`); + } fs.writeFileSync(distFile, output, "utf8"); - fs.writeFileSync(distMinFile, minifyCss(output), "utf8"); + fs.writeFileSync(distMinFile, minified.styles, "utf8"); }); const genericFile = path.join(DIST_DIR, "y2k-alerts-generic.css"); @@ -74,20 +65,40 @@ function buildCss() { } } -function buildJs() { +async function buildJs() { const jsBundle = readFiles(JS_DIR, JS_FILES); const distFile = path.join(DIST_DIR, "y2k-alerts.js"); const distMinFile = path.join(DIST_DIR, "y2k-alerts.min.js"); + const minified = await minify(jsBundle, { + compress: true, + mangle: true, + format: { + comments: false + } + }); + + if (!minified.code) { + throw new Error("JS minification failed: terser returned empty output."); + } fs.writeFileSync(distFile, jsBundle, "utf8"); - fs.writeFileSync(distMinFile, minifyJs(jsBundle), "utf8"); + fs.writeFileSync(distMinFile, minified.code, "utf8"); } -function build() { +async function build() { ensureDir(DIST_DIR); buildCss(); - buildJs(); + await buildJs(); console.log("Built y2k-alerts assets in dist/"); } -build(); +if (require.main === module) { + build().catch((error) => { + console.error(error); + process.exit(1); + }); +} + +module.exports = { + build +}; diff --git a/scripts/watch.js b/scripts/watch.js new file mode 100644 index 0000000..c581e39 --- /dev/null +++ b/scripts/watch.js @@ -0,0 +1,69 @@ +const path = require("path"); +const chokidar = require("chokidar"); +const browserSync = require("browser-sync").create(); +const { build } = require("./build"); + +const ROOT_DIR = path.resolve(__dirname, ".."); +const SOURCE_GLOBS = [ + path.join(ROOT_DIR, "css/**/*.css"), + path.join(ROOT_DIR, "js/**/*.js") +]; +const EXAMPLE_GLOBS = [ + path.join(ROOT_DIR, "examples/**/*.html") +]; + +let isBuilding = false; +let hasPendingBuild = false; + +async function queueBuild(trigger) { + if (isBuilding) { + hasPendingBuild = true; + return; + } + + isBuilding = true; + + try { + await build(); + console.log(`[watch] Built after ${trigger}`); + browserSync.reload(); + } catch (error) { + console.error("[watch] Build failed"); + console.error(error); + } finally { + isBuilding = false; + } + + if (hasPendingBuild) { + hasPendingBuild = false; + await queueBuild("queued change"); + } +} + +async function start() { + await build(); + + browserSync.init({ + server: ROOT_DIR, + startPath: "examples/generic.html", + notify: false, + open: false + }); + + chokidar.watch(SOURCE_GLOBS, { ignoreInitial: true }).on("all", (event, filePath) => { + const relativePath = path.relative(ROOT_DIR, filePath); + queueBuild(`${event}: ${relativePath}`); + }); + + chokidar.watch(EXAMPLE_GLOBS, { ignoreInitial: true }).on("all", () => { + browserSync.reload(); + }); + + console.log("[watch] Watching css/, js/, and examples/."); +} + +start().catch((error) => { + console.error("[watch] Failed to start"); + console.error(error); + process.exit(1); +});