This commit is contained in:
2026-02-27 12:13:52 +02:00
parent 200058ba03
commit 279f40486b
5 changed files with 127 additions and 25 deletions

View File

@@ -33,7 +33,10 @@
var alertInstance = new y2kAlert( var alertInstance = new y2kAlert(
"Storage Warning", "Storage Warning",
Y2K.TYPE_WARNING, Y2K.TYPE_WARNING,
"Disk space is running low." "Disk space is running low.",
{
closeOnBackdropClick: true
}
); );
alertInstance.addEventListener("submit", function (event) { alertInstance.addEventListener("submit", function (event) {

View File

@@ -10,7 +10,9 @@
this.title = title || "Alert"; this.title = title || "Alert";
this.type = type || Y2K.TYPE_INFO; this.type = type || Y2K.TYPE_INFO;
this.message = message || ""; this.message = message || "";
this.options = options || {}; this.options = Object.assign({
closeOnBackdropClick: false
}, options || {});
this.isVisible = false; this.isVisible = false;
this.inputElement = null; this.inputElement = null;
this.overlayElement = null; this.overlayElement = null;
@@ -101,6 +103,16 @@
self.submit(); self.submit();
}); });
this.overlayElement.addEventListener("click", function (event) {
if (!self.options.closeOnBackdropClick) {
return;
}
if (event.target === self.overlayElement) {
self.close("backdrop");
}
});
if (this.inputElement) { if (this.inputElement) {
this.inputElement.addEventListener("keydown", function (event) { this.inputElement.addEventListener("keydown", function (event) {
if (event.key === "Enter") { if (event.key === "Enter") {

View File

@@ -26,6 +26,13 @@
"style": "dist/y2k-alerts.css", "style": "dist/y2k-alerts.css",
"scripts": { "scripts": {
"build": "node scripts/build.js", "build": "node scripts/build.js",
"watch": "node scripts/watch.js",
"test": "npm run build" "test": "npm run build"
},
"devDependencies": {
"browser-sync": "^3.0.3",
"chokidar": "^3.6.0",
"clean-css": "^5.3.3",
"terser": "^5.31.2"
} }
} }

View File

@@ -1,5 +1,7 @@
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const CleanCSS = require("clean-css");
const { minify } = require("terser");
const ROOT_DIR = path.resolve(__dirname, ".."); const ROOT_DIR = path.resolve(__dirname, "..");
const DIST_DIR = path.join(ROOT_DIR, "dist"); const DIST_DIR = path.join(ROOT_DIR, "dist");
@@ -20,24 +22,8 @@ function readFiles(folder, files) {
.join("\n\n"); .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() { function buildCss() {
const cssMinifier = new CleanCSS({ level: 2 });
const baseCss = readFiles(BASE_CSS_DIR, BASE_CSS_FILES); const baseCss = readFiles(BASE_CSS_DIR, BASE_CSS_FILES);
const themeFolders = fs const themeFolders = fs
.readdirSync(THEMES_DIR, { withFileTypes: true }) .readdirSync(THEMES_DIR, { withFileTypes: true })
@@ -57,9 +43,14 @@ function buildCss() {
const distFile = path.join(DIST_DIR, `y2k-alerts-${themeName}.css`); const distFile = path.join(DIST_DIR, `y2k-alerts-${themeName}.css`);
const distMinFile = path.join(DIST_DIR, `y2k-alerts-${themeName}.min.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(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"); 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 jsBundle = readFiles(JS_DIR, JS_FILES);
const distFile = path.join(DIST_DIR, "y2k-alerts.js"); const distFile = path.join(DIST_DIR, "y2k-alerts.js");
const distMinFile = path.join(DIST_DIR, "y2k-alerts.min.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(distFile, jsBundle, "utf8");
fs.writeFileSync(distMinFile, minifyJs(jsBundle), "utf8"); fs.writeFileSync(distMinFile, minified.code, "utf8");
} }
function build() { async function build() {
ensureDir(DIST_DIR); ensureDir(DIST_DIR);
buildCss(); buildCss();
buildJs(); await buildJs();
console.log("Built y2k-alerts assets in dist/"); 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
};

69
scripts/watch.js Normal file
View File

@@ -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);
});