diff --git a/build.js b/build.js index a69998a..23099c5 100644 --- a/build.js +++ b/build.js @@ -1,302 +1,50 @@ -// IMPORTS +const assproc = require('@railcomm/assproc'); +const { join: pathJoin } = require('path'); const fs = require('fs'); -const swc = require('@swc/core'); -const path = require('path'); -const util = require('util'); -const postcss = require('postcss'); -const htmlminify = require('html-minifier-terser').minify; -const childProcess = require('child_process'); -const utils = require('./src/utils.js'); -const assproc = require('./src/assproc.js'); +const exec = require('util').promisify(require('child_process').exec); - -// CONFIG -const rootDir = __dirname; -const configFile = path.join(rootDir, 'config/config.json'); -const srcDir = path.join(rootDir, 'src'); -const pubDir = path.join(rootDir, 'public'); -const pubAssetsDir = path.join(pubDir, 'assets'); - -const isDebugBuild = fs.existsSync(path.join(rootDir, '.debug')); - -const buildTasks = { - js: [ - { source: 'proto.js', target: '/assets', name: 'proto.{hash}.js', buildVar: 'MAMI_PROTO_JS', buildVarsTarget: 'self' }, - { source: 'mami.js', target: '/assets', name: 'mami.{hash}.js', buildVar: 'MAMI_MAIN_JS' }, - { source: 'init.js', target: '/assets', name: 'init.{hash}.js', es: 'es5' }, - ], - css: [ - { source: 'mami.css', target: '/assets', name: 'mami.{hash}.css' }, - ], - html: [ - { source: 'mami.html', target: '/', name: 'index.html' }, - ], - webmanifest: [ - { source: 'mami.webmanifest', target: '/', name: 'mami.webmanifest', icons: '/icons' } - ], -}; - - -// PREP -const config = JSON.parse(fs.readFileSync(configFile)); - -const postcssPlugins = [ require('autoprefixer')({ remove: false }) ]; -if(!isDebugBuild) - postcssPlugins.push(require('cssnano')({ - preset: [ - 'cssnano-preset-default', - { - minifyGradients: false, - reduceIdents: false, - zindex: true, - } - ], - })); - -const swcJscOptions = { - target: 'es2020', - loose: false, - externalHelpers: false, - keepClassNames: true, - preserveAllComments: false, - transform: {}, - parser: { - syntax: 'ecmascript', - jsx: true, - dynamicImport: false, - privateMethod: false, - functionBind: false, - exportDefaultFrom: false, - exportNamespaceFrom: false, - decorators: false, - decoratorsBeforeExport: false, - topLevelAwait: true, - importMeta: false, - }, - transform: { - react: { - runtime: 'classic', - pragma: '$er', - }, - }, -}; - -const htmlMinifyOptions = { - collapseBooleanAttributes: true, - collapseWhitespace: true, - conservativeCollapse: false, - decodeEntities: false, - quoteCharacter: '"', - removeAttributeQuotes: true, - removeComments: true, - removeEmptyAttributes: true, - removeOptionalTags: true, - removeScriptTypeAttributes: true, - removeStyleLinkTypeAttributes: true, - sortAttributes: true, - sortClassName: true, -}; - - -// BUILD (async () => { - const htmlVars = { 'title': config.title }; - const buildVars = { - FUTAMI_DEBUG: isDebugBuild, - FUTAMI_URL: config.common_url, - MAMI_URL: config.modern_url, - AMI_URL: config.compat_url, - GIT_HASH: await (() => { - return new Promise((resolve, reject) => { - childProcess.exec('git log --pretty="%H" -n1 HEAD', (err, stdout) => { - if(err) reject(err); - else resolve(stdout.trim()); - }); - }); - })(), + const config = JSON.parse(fs.readFileSync(pathJoin(__dirname, 'config/config.json'))); + const isDebug = fs.existsSync(pathJoin(__dirname, '.debug')); + + const env = { + root: __dirname, + source: pathJoin(__dirname, 'src'), + public: pathJoin(__dirname, 'public'), + debug: isDebug, + swc: { + es: 'es2020', + }, + vars: { + html: { + title: config.title, + }, + build: { + FUTAMI_DEBUG: isDebug, + FUTAMI_URL: config.common_url, + MAMI_URL: config.modern_url, + AMI_URL: config.compat_url, + GIT_HASH: (await exec('git log --pretty="%H" -n1 HEAD')).stdout, + }, + }, }; - console.log('Ensuring assets directory exists...'); - fs.mkdirSync(pubAssetsDir, { recursive: true }); + const tasks = { + js: [ + { source: 'proto.js', target: '/assets', name: 'proto.{hash}.js', vars: { build: 'MAMI_PROTO_JS', html: ':source' } }, + { source: 'mami.js', target: '/assets', name: 'mami.{hash}.js', vars: { build: 'MAMI_MAIN_JS', html: ':source' } }, + { source: 'init.js', target: '/assets', name: 'init.{hash}.js', es: 'es5', vars: { html: ':source' } }, + ], + css: [ + { source: 'mami.css', target: '/assets', name: 'mami.{hash}.css', vars: { html: ':source' } }, + ], + webmanifest: [ + { source: 'mami.webmanifest', target: '/', name: 'mami.webmanifest', icons: '/icons', vars: { html: ':source' }, body: { name: config.title, short_name: config.title } } + ], + html: [ + { source: 'mami.html', target: '/', name: 'index.html', template: 'html' }, + ], + }; - - console.log(); - console.log('JS assets'); - for(const info of buildTasks.js) { - console.log(`=> Building ${info.source}...`); - - let origTarget = undefined; - if('es' in info) { - origTarget = swcJscOptions.target; - swcJscOptions.target = info.es; - } - - const assprocOpts = { - prefix: '#', - entry: info.entry || 'main.js', - buildVars: buildVars, - }; - const swcOpts = { - filename: info.source, - sourceMaps: false, - isModule: false, - minify: !isDebugBuild, - jsc: swcJscOptions, - }; - - const pubName = await assproc.process(path.join(srcDir, info.source), assprocOpts) - .then(output => swc.transform(output, swcOpts)) - .then(output => { - const name = utils.strtr(info.name, { hash: utils.shortHash(output.code) }); - const pubName = path.join(info.target || '', name); - - console.log(` Saving to ${pubName}...`); - fs.writeFileSync(path.join(pubDir, pubName), output.code); - - return pubName; - }); - - if(origTarget !== undefined) - swcJscOptions.target = origTarget; - - htmlVars[info.source] = pubName; - if(typeof info.buildVar === 'string') - buildVars[info.buildVar] = pubName; - } - - - console.log(); - console.log('CSS assets'); - for(const info of buildTasks.css) { - console.log(`=> Building ${info.source}...`); - - const sourcePath = path.join(srcDir, info.source); - const assprocOpts = { - prefix: '@', - entry: info.entry || 'main.css', - }; - const postcssOpts = { from: sourcePath }; - - htmlVars[info.source] = await assproc.process(sourcePath, assprocOpts) - .then(output => postcss(postcssPlugins).process(output, postcssOpts) - .then(output => { - const name = utils.strtr(info.name, { hash: utils.shortHash(output.css) }); - const pubName = path.join(info.target || '', name); - - console.log(` Saving to ${pubName}...`); - fs.writeFileSync(path.join(pubDir, pubName), output.css); - - return pubName; - })); - } - - - console.log(); - console.log('Webmanifest assets...'); - for(const info of buildTasks.webmanifest) { - console.log(`=> Building ${info.source}...`); - - try { - const body = JSON.parse(fs.readFileSync(path.join(srcDir, info.source))); - - body.name = config.title; - body.short_name = config.title; - - if(typeof info.icons === 'string') { - const iconsDir = path.join(pubDir, info.icons); - - if(fs.existsSync(iconsDir)) { - const files = (await fs.promises.readdir(iconsDir)).sort((a, b) => a.localeCompare(b, undefined, { - numeric: true, - sensitivity: 'base', - })); - body.icons = []; - - for(const file of files) { - if(!file.endsWith('.png')) - continue; - - const icon = { - src: path.join(info.icons, file), - type: 'image/png', - }; - - if(file[0] !== 'c') { - if(file[0] === 'm') - icon.purpose = 'maskable'; - else if(file[0] === 'w') - icon.purpose = 'monochrome'; - else continue; - } - - let res = ''; - for(let i = 1; i < file.length; ++i) { - if(file[i] === 'x') - break; - res += file[i]; - } - - if(res.length > 0) - icon.sizes = `${res}x${res}`; - - body.icons.push(icon); - } - } - } - - const data = JSON.stringify(body); - - const name = utils.strtr(info.name, { hash: utils.shortHash(data) }); - const pubName = path.join(info.target || '', name); - - console.log(` Saving to ${pubName}...`); - - const fullPath = path.join(pubDir, pubName); - const dirPath = path.dirname(fullPath); - if(!fs.existsSync(dirPath)) - fs.mkdirSync(dirPath, { recursive: true }); - - fs.writeFileSync(fullPath, data); - htmlVars[info.source] = pubName; - } catch(err) { - console.error(err); - } - } - - - console.log(); - console.log('HTML assets'); - for(const info of buildTasks.html) { - console.log(`=> Building ${info.source}...`); - - try { - let data = fs.readFileSync(path.join(srcDir, info.source)); - - data = utils.strtr(data, htmlVars); - - if(!isDebugBuild) - data = await htmlminify(data, htmlMinifyOptions); - - const name = utils.strtr(info.name, { hash: utils.shortHash(data) }); - const pubName = path.join(info.target || '', name); - - console.log(` Saving to ${pubName}...`); - - const fullPath = path.join(pubDir, pubName); - const dirPath = path.dirname(fullPath); - if(!fs.existsSync(dirPath)) - fs.mkdirSync(dirPath, { recursive: true }); - - fs.writeFileSync(fullPath, data); - - htmlVars[info.source] = pubName; - } catch(err) { - console.error(err); - } - } - - - console.log(); - console.log('Cleaning up old builds...'); - assproc.housekeep(pubAssetsDir); + await assproc.process(env, tasks); })(); diff --git a/package-lock.json b/package-lock.json index 1e8e6e0..c6942d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,7 @@ "packages": { "": { "dependencies": { - "@swc/core": "^1.5.24", - "autoprefixer": "^10.4.19", - "cssnano": "^6.1.2", - "html-minifier-terser": "^7.2.0", - "postcss": "^8.4.38" + "@railcomm/assproc": "^1.0.0" } }, "node_modules/@jridgewell/gen-mapping": { @@ -70,15 +66,28 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@railcomm/assproc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@railcomm/assproc/-/assproc-1.0.0.tgz", + "integrity": "sha512-u8BQht9di9yps7eVYYXbUaOeHCcbR8dKNLuc/KZ+E4uhPnFJ414WaIMH6h4QsMbDY7tAFehqFims7zM949nHGg==", + "license": "BSD-3-Clause", + "dependencies": { + "@swc/core": "^1.5.25", + "autoprefixer": "^10.4.19", + "cssnano": "^7.0.2", + "html-minifier-terser": "^7.2.0", + "postcss": "^8.4.38" + } + }, "node_modules/@swc/core": { - "version": "1.5.24", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.24.tgz", - "integrity": "sha512-Eph9zvO4xvqWZGVzTdtdEJ0Vqf0VIML/o/e4Qd2RLOqtfgnlRi7avmMu5C0oqciJ0tk+hqdUKVUZ4JPoPaiGvQ==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.6.3.tgz", + "integrity": "sha512-mZpei+LqE+AL+nwgERMQey9EJA9/yhHTN6nwbobH5GnSij/lhfTdGfAb1iumOrroqEcXbHUaK//7wOw7DjBGdA==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.7" + "@swc/types": "^0.1.8" }, "engines": { "node": ">=10" @@ -88,16 +97,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.5.24", - "@swc/core-darwin-x64": "1.5.24", - "@swc/core-linux-arm-gnueabihf": "1.5.24", - "@swc/core-linux-arm64-gnu": "1.5.24", - "@swc/core-linux-arm64-musl": "1.5.24", - "@swc/core-linux-x64-gnu": "1.5.24", - "@swc/core-linux-x64-musl": "1.5.24", - "@swc/core-win32-arm64-msvc": "1.5.24", - "@swc/core-win32-ia32-msvc": "1.5.24", - "@swc/core-win32-x64-msvc": "1.5.24" + "@swc/core-darwin-arm64": "1.6.3", + "@swc/core-darwin-x64": "1.6.3", + "@swc/core-linux-arm-gnueabihf": "1.6.3", + "@swc/core-linux-arm64-gnu": "1.6.3", + "@swc/core-linux-arm64-musl": "1.6.3", + "@swc/core-linux-x64-gnu": "1.6.3", + "@swc/core-linux-x64-musl": "1.6.3", + "@swc/core-win32-arm64-msvc": "1.6.3", + "@swc/core-win32-ia32-msvc": "1.6.3", + "@swc/core-win32-x64-msvc": "1.6.3" }, "peerDependencies": { "@swc/helpers": "*" @@ -109,9 +118,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.5.24", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.24.tgz", - "integrity": "sha512-M7oLOcC0sw+UTyAuL/9uyB9GeO4ZpaBbH76JSH6g1m0/yg7LYJZGRmplhDmwVSDAR5Fq4Sjoi1CksmmGkgihGA==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.6.3.tgz", + "integrity": "sha512-3r7cJf1BcE30iyF1rnOSKrEzIR+cqnyYSZvivrm62TZdXVsIjfXe1xulsKGxZgNeLY5erIu7ukvMvBvPhnQvqA==", "cpu": [ "arm64" ], @@ -125,9 +134,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.5.24", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.5.24.tgz", - "integrity": "sha512-MfcFjGGYognpSBSos2pYUNYJSmqEhuw5ceGr6qAdME7ddbjGXliza4W6FggsM+JnWwpqa31+e7/R+GetW4WkaQ==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.6.3.tgz", + "integrity": "sha512-8GLZ23IgVpF5xh2SbS5ZW/12/EEBuRU1hFOLB5rKERJU0y1RJ6YhDMf/FuOWhfHQcFM7TeedBwHIzaF+tdKKlw==", "cpu": [ "x64" ], @@ -141,9 +150,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.5.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.24.tgz", - "integrity": "sha512-amI2pwtcWV3E/m/nf+AQtn1LWDzKLZyjCmWd3ms7QjEueWYrY8cU1Y4Wp7wNNsxIoPOi8zek1Uj2wwFD/pttNQ==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.6.3.tgz", + "integrity": "sha512-VQ/bduX7WhLOlGbJLMG7UH0LBehjjx43R4yuk55rjjJLqpvX5fQzMsWhQdIZ5vsc+4ORzdgtEAlpumTv6bsD1A==", "cpu": [ "arm" ], @@ -157,9 +166,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.5.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.24.tgz", - "integrity": "sha512-sTSvmqMmgT1ynH/nP75Pc51s+iT4crZagHBiDOf5cq+kudUYjda9lWMs7xkXB/TUKFHPCRK0HGunl8bkwiIbuw==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.6.3.tgz", + "integrity": "sha512-jHIQ/PCwtdDBIF/BiC5DochswuCAIW/T5skJ+eDMbta7+QtEnZCXTZWpT5ORoEY/gtsE2fjpOA4TS6fBBvXqUw==", "cpu": [ "arm64" ], @@ -173,9 +182,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.5.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.24.tgz", - "integrity": "sha512-vd2/hfOBGbrX21FxsFdXCUaffjkHvlZkeE2UMRajdXifwv79jqOHIJg3jXG1F3ZrhCghCzirFts4tAZgcG8XWg==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.6.3.tgz", + "integrity": "sha512-gA6velEUD27Dwu0BlR9hCcFzkWq2YL2pDAU5qbgeuGhaMiUCBssfqTQB+2ctEnV+AZx+hSMJOHvtA+uFZjfRrw==", "cpu": [ "arm64" ], @@ -189,9 +198,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.5.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.24.tgz", - "integrity": "sha512-Zrdzi7NqzQxm2BvAG5KyOSBEggQ7ayrxh599AqqevJmsUXJ8o2nMiWQOBvgCGp7ye+Biz3pvZn1EnRzAp+TpUg==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.6.3.tgz", + "integrity": "sha512-fy4qoBDr5I8r+ZNCZxs/oZcmu4j/8mtSud6Ka102DaSxEjNg0vfIdo9ITsVIPsofhUTmDKjQsPB2O7YUlJAioQ==", "cpu": [ "x64" ], @@ -205,9 +214,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.5.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.24.tgz", - "integrity": "sha512-1F8z9NRi52jdZQCGc5sflwYSctL6omxiVmIFVp8TC9nngjQKc00TtX/JC2Eo2HwvgupkFVl5YQJidAck9YtmJw==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.6.3.tgz", + "integrity": "sha512-c/twcMbq/Gpq47G+b3kWgoaCujpXO11aRgJx6am+CprvP4uNeBHEpQkxD+DQmdWFHisZd0i9GB8NG3e7L9Rz9Q==", "cpu": [ "x64" ], @@ -221,9 +230,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.5.24", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.24.tgz", - "integrity": "sha512-cKpP7KvS6Xr0jFSTBXY53HZX/YfomK5EMQYpCVDOvfsZeYHN20sQSKXfpVLvA/q2igVt1zzy1XJcOhpJcgiKLg==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.6.3.tgz", + "integrity": "sha512-y6RxMtX45acReQmzkxcEfJscfBXce6QjuNgWQHHs9exA592BZzmolDUwgmAyjyvopz1lWX+KdymdZFKvuDSx4w==", "cpu": [ "arm64" ], @@ -237,9 +246,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.5.24", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.24.tgz", - "integrity": "sha512-IoPWfi0iwqjZuf7gE223+B97/ZwkKbu7qL5KzGP7g3hJrGSKAvv7eC5Y9r2iKKtLKyv5R/T6Ho0kFR/usi7rHw==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.6.3.tgz", + "integrity": "sha512-41h7z3xgukl1HDDwhquaeOPSP1OWeHl+mWKnJVmmwd3ui/oowUDCO856qa6JagBgPSnAGfyXwv6vthuXwyCcWA==", "cpu": [ "ia32" ], @@ -253,9 +262,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.5.24", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.24.tgz", - "integrity": "sha512-zHgF2k1uVJL8KIW+PnVz1To4a3Cz9THbh2z2lbehaF/gKHugH4c3djBozU4das1v35KOqf5jWIEviBLql2wDLQ==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.6.3.tgz", + "integrity": "sha512-//bnwo9b8Vp1ED06eXCHyGZ5xIpdkQgg2fuFDdtd1FITl7r5bdQh2ryRzPiKiGwgXZwZQitUshI4JeEX9IuW+Q==", "cpu": [ "x64" ], @@ -275,9 +284,9 @@ "license": "Apache-2.0" }, "node_modules/@swc/types": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.7.tgz", - "integrity": "sha512-scHWahbHF0eyj3JsxG9CFJgFdFNaVQCNAimBlT6PzS3n/HptxqREjsm4OH6AN3lYcffZYSPxXW8ua2BEHp0lJQ==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.8.tgz", + "integrity": "sha512-RNFA3+7OJFNYY78x0FYwi1Ow+iF1eF5WvmfY1nXPOEH4R2p/D4Cr1vzje7dNAI2aLFqpv8Wyz4oKSWqIZArpQA==", "license": "Apache-2.0", "dependencies": { "@swc/counter": "^0.1.3" @@ -293,9 +302,9 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -348,9 +357,9 @@ "license": "ISC" }, "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.23.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", + "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", "funding": [ { "type": "opencollective", @@ -367,10 +376,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", + "caniuse-lite": "^1.0.30001629", + "electron-to-chromium": "^1.4.796", "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "update-browserslist-db": "^1.0.16" }, "bin": { "browserslist": "cli.js" @@ -408,9 +417,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001627", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001627.tgz", - "integrity": "sha512-4zgNiB8nTyV/tHhwZrFs88ryjls/lHiqFhrxCW4qSTeuRByBVnPYpDInchOIySWknznucaf31Z4KYqjfbrecVw==", + "version": "1.0.30001636", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", + "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==", "funding": [ { "type": "opencollective", @@ -520,16 +529,16 @@ } }, "node_modules/cssnano": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", - "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.0.3.tgz", + "integrity": "sha512-lsekJctOTqdCn4cNrtrSwsuMR/fHC+oiVMHkp/OugBWtwjH8XJag1/OtGaYJGtz0un1fQcRy4ryfYTQsfh+KSQ==", "license": "MIT", "dependencies": { - "cssnano-preset-default": "^6.1.2", - "lilconfig": "^3.1.1" + "cssnano-preset-default": "^7.0.3", + "lilconfig": "^3.1.2" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "funding": { "type": "opencollective", @@ -540,56 +549,56 @@ } }, "node_modules/cssnano-preset-default": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", - "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.3.tgz", + "integrity": "sha512-dQ3Ba1p/oewICp/szF1XjFFgql8OlOBrI2YNBUUwhHQnJNoMOcQTa+Bi7jSJN8r/eM1egW0Ud1se/S7qlduWKA==", "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", + "browserslist": "^4.23.1", "css-declaration-sorter": "^7.2.0", - "cssnano-utils": "^4.0.2", - "postcss-calc": "^9.0.1", - "postcss-colormin": "^6.1.0", - "postcss-convert-values": "^6.1.0", - "postcss-discard-comments": "^6.0.2", - "postcss-discard-duplicates": "^6.0.3", - "postcss-discard-empty": "^6.0.3", - "postcss-discard-overridden": "^6.0.2", - "postcss-merge-longhand": "^6.0.5", - "postcss-merge-rules": "^6.1.1", - "postcss-minify-font-values": "^6.1.0", - "postcss-minify-gradients": "^6.0.3", - "postcss-minify-params": "^6.1.0", - "postcss-minify-selectors": "^6.0.4", - "postcss-normalize-charset": "^6.0.2", - "postcss-normalize-display-values": "^6.0.2", - "postcss-normalize-positions": "^6.0.2", - "postcss-normalize-repeat-style": "^6.0.2", - "postcss-normalize-string": "^6.0.2", - "postcss-normalize-timing-functions": "^6.0.2", - "postcss-normalize-unicode": "^6.1.0", - "postcss-normalize-url": "^6.0.2", - "postcss-normalize-whitespace": "^6.0.2", - "postcss-ordered-values": "^6.0.2", - "postcss-reduce-initial": "^6.1.0", - "postcss-reduce-transforms": "^6.0.2", - "postcss-svgo": "^6.0.3", - "postcss-unique-selectors": "^6.0.4" + "cssnano-utils": "^5.0.0", + "postcss-calc": "^10.0.0", + "postcss-colormin": "^7.0.1", + "postcss-convert-values": "^7.0.1", + "postcss-discard-comments": "^7.0.1", + "postcss-discard-duplicates": "^7.0.0", + "postcss-discard-empty": "^7.0.0", + "postcss-discard-overridden": "^7.0.0", + "postcss-merge-longhand": "^7.0.2", + "postcss-merge-rules": "^7.0.2", + "postcss-minify-font-values": "^7.0.0", + "postcss-minify-gradients": "^7.0.0", + "postcss-minify-params": "^7.0.1", + "postcss-minify-selectors": "^7.0.2", + "postcss-normalize-charset": "^7.0.0", + "postcss-normalize-display-values": "^7.0.0", + "postcss-normalize-positions": "^7.0.0", + "postcss-normalize-repeat-style": "^7.0.0", + "postcss-normalize-string": "^7.0.0", + "postcss-normalize-timing-functions": "^7.0.0", + "postcss-normalize-unicode": "^7.0.1", + "postcss-normalize-url": "^7.0.0", + "postcss-normalize-whitespace": "^7.0.0", + "postcss-ordered-values": "^7.0.1", + "postcss-reduce-initial": "^7.0.1", + "postcss-reduce-transforms": "^7.0.0", + "postcss-svgo": "^7.0.1", + "postcss-unique-selectors": "^7.0.1" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/cssnano-utils": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", - "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-5.0.0.tgz", + "integrity": "sha512-Uij0Xdxc24L6SirFr25MlwC2rCFX6scyUmuKpzI+JQ7cyqDEwD42fJ0xfB3yLfOnRDU5LKGgjQ9FA6LYh76GWQ==", "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" @@ -694,9 +703,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.789", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.789.tgz", - "integrity": "sha512-0VbyiaXoT++Fi2vHGo2ThOeS6X3vgRCWrjPeO2FeIAWL6ItiSJ9BqlH8LfCXe3X1IdcG+S0iLoNaxQWhfZoGzQ==", + "version": "1.4.806", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.806.tgz", + "integrity": "sha512-nkoEX2QIB8kwCOtvtgwhXWy2IHVcOLQZu9Qo36uaGB835mdX/h8uLRlosL6QIhLVUnAiicXRW00PwaPZC74Nrg==", "license": "ISC" }, "node_modules/entities": { @@ -755,9 +764,9 @@ } }, "node_modules/lilconfig": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", - "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", "license": "MIT", "engines": { "node": ">=14" @@ -903,376 +912,380 @@ } }, "node_modules/postcss-calc": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", - "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.0.0.tgz", + "integrity": "sha512-OmjhudoNTP0QleZCwl1i6NeBwN+5MZbY5ersLZz69mjJiDVv/p57RjRuKDkHeDWr4T+S97wQfsqRTNoDHB2e3g==", "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.11", + "postcss-selector-parser": "^6.0.16", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12 || ^20.9 || >=22.0" }, "peerDependencies": { - "postcss": "^8.2.2" + "postcss": "^8.4.38" } }, "node_modules/postcss-colormin": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", - "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.1.tgz", + "integrity": "sha512-uszdT0dULt3FQs47G5UHCduYK+FnkLYlpu1HpWu061eGsKZ7setoG7kA+WC9NQLsOJf69D5TxGHgnAdRgylnFQ==", "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", + "browserslist": "^4.23.1", "caniuse-api": "^3.0.0", "colord": "^2.9.3", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-convert-values": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", - "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.1.tgz", + "integrity": "sha512-9x2ofb+hYPwHWMlWAzyWys2yMDZYGfkX9LodbaVTmLdlupmtH2AGvj8Up95wzzNPRDEzPIxQIkUaPJew3bT6xA==", "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", + "browserslist": "^4.23.1", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-discard-comments": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", - "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.1.tgz", + "integrity": "sha512-GVrQxUOhmle1W6jX2SvNLt4kmN+JYhV7mzI6BMnkAWR9DtVvg8e67rrV0NfdWhn7x1zxvzdWkMBPdBDCls+uwQ==", "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.0" + }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-discard-duplicates": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", - "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.0.tgz", + "integrity": "sha512-bAnSuBop5LpAIUmmOSsuvtKAAKREB6BBIYStWUTGq8oG5q9fClDMMuY8i4UPI/cEcDx2TN+7PMnXYIId20UVDw==", "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-discard-empty": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", - "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.0.tgz", + "integrity": "sha512-e+QzoReTZ8IAwhnSdp/++7gBZ/F+nBq9y6PomfwORfP7q9nBpK5AMP64kOt0bA+lShBFbBDcgpJ3X4etHg4lzA==", "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-discard-overridden": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", - "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-7.0.0.tgz", + "integrity": "sha512-GmNAzx88u3k2+sBTZrJSDauR0ccpE24omTQCVmaTTZFz1du6AasspjaUPMJ2ud4RslZpoFKyf+6MSPETLojc6w==", "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-merge-longhand": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", - "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.2.tgz", + "integrity": "sha512-06vrW6ZWi9qeP7KMS9fsa9QW56+tIMW55KYqF7X3Ccn+NI2pIgPV6gFfvXTMQ05H90Y5DvnCDPZ2IuHa30PMUg==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.1.1" + "stylehacks": "^7.0.2" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-merge-rules": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", - "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.2.tgz", + "integrity": "sha512-VAR47UNvRsdrTHLe7TV1CeEtF9SJYR5ukIB9U4GZyZOptgtsS20xSxy+k5wMrI3udST6O1XuIn7cjQkg7sDAAw==", "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", + "browserslist": "^4.23.1", "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.2", - "postcss-selector-parser": "^6.0.16" + "cssnano-utils": "^5.0.0", + "postcss-selector-parser": "^6.1.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-minify-font-values": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", - "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-7.0.0.tgz", + "integrity": "sha512-2ckkZtgT0zG8SMc5aoNwtm5234eUx1GGFJKf2b1bSp8UflqaeFzR50lid4PfqVI9NtGqJ2J4Y7fwvnP/u1cQog==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-minify-gradients": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", - "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.0.tgz", + "integrity": "sha512-pdUIIdj/C93ryCHew0UgBnL2DtUS3hfFa5XtERrs4x+hmpMYGhbzo6l/Ir5de41O0GaKVpK1ZbDNXSY6GkXvtg==", "license": "MIT", "dependencies": { "colord": "^2.9.3", - "cssnano-utils": "^4.0.2", + "cssnano-utils": "^5.0.0", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-minify-params": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", - "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.1.tgz", + "integrity": "sha512-e+Xt8xErSRPgSRFxHeBCSxMiO8B8xng7lh8E0A5ep1VfwYhY8FXhu4Q3APMjgx9YDDbSp53IBGENrzygbUvgUQ==", "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", - "cssnano-utils": "^4.0.2", + "browserslist": "^4.23.1", + "cssnano-utils": "^5.0.0", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-minify-selectors": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", - "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.2.tgz", + "integrity": "sha512-dCzm04wqW1uqLmDZ41XYNBJfjgps3ZugDpogAmJXoCb5oCiTzIX4oPXXKxDpTvWOnKxQKR4EbV4ZawJBLcdXXA==", "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.16" + "cssesc": "^3.0.0", + "postcss-selector-parser": "^6.1.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-charset": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", - "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-7.0.0.tgz", + "integrity": "sha512-ABisNUXMeZeDNzCQxPxBCkXexvBrUHV+p7/BXOY+ulxkcjUZO0cp8ekGBwvIh2LbCwnWbyMPNJVtBSdyhM2zYQ==", "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-display-values": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", - "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.0.tgz", + "integrity": "sha512-lnFZzNPeDf5uGMPYgGOw7v0BfB45+irSRz9gHQStdkkhiM0gTfvWkWB5BMxpn0OqgOQuZG/mRlZyJxp0EImr2Q==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-positions": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", - "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-7.0.0.tgz", + "integrity": "sha512-I0yt8wX529UKIGs2y/9Ybs2CelSvItfmvg/DBIjTnoUSrPxSV7Z0yZ8ShSVtKNaV/wAY+m7bgtyVQLhB00A1NQ==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-repeat-style": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", - "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.0.tgz", + "integrity": "sha512-o3uSGYH+2q30ieM3ppu9GTjSXIzOrRdCUn8UOMGNw7Af61bmurHTWI87hRybrP6xDHvOe5WlAj3XzN6vEO8jLw==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-string": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", - "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-7.0.0.tgz", + "integrity": "sha512-w/qzL212DFVOpMy3UGyxrND+Kb0fvCiBBujiaONIihq7VvtC7bswjWgKQU/w4VcRyDD8gpfqUiBQ4DUOwEJ6Qg==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-timing-functions": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", - "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.0.tgz", + "integrity": "sha512-tNgw3YV0LYoRwg43N3lTe3AEWZ66W7Dh7lVEpJbHoKOuHc1sLrzMLMFjP8SNULHaykzsonUEDbKedv8C+7ej6g==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-unicode": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", - "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.1.tgz", + "integrity": "sha512-PTPGdY9xAkTw+8ZZ71DUePb7M/Vtgkbbq+EoI33EuyQEzbKemEQMhe5QSr0VP5UfZlreANDPxSfcdSprENcbsg==", "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", + "browserslist": "^4.23.1", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-url": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", - "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-7.0.0.tgz", + "integrity": "sha512-+d7+PpE+jyPX1hDQZYG+NaFD+Nd2ris6r8fPTBAjE8z/U41n/bib3vze8x7rKs5H1uEw5ppe9IojewouHk0klQ==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-whitespace": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", - "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.0.tgz", + "integrity": "sha512-37/toN4wwZErqohedXYqWgvcHUGlT8O/m2jVkAfAe9Bd4MzRqlBmXrJRePH0e9Wgnz2X7KymTgTOaaFizQe3AQ==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-ordered-values": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", - "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-7.0.1.tgz", + "integrity": "sha512-irWScWRL6nRzYmBOXReIKch75RRhNS86UPUAxXdmW/l0FcAsg0lvAXQCby/1lymxn/o0gVa6Rv/0f03eJOwHxw==", "license": "MIT", "dependencies": { - "cssnano-utils": "^4.0.2", + "cssnano-utils": "^5.0.0", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-reduce-initial": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", - "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.1.tgz", + "integrity": "sha512-0JDUSV4bGB5FGM5g8MkS+rvqKukJZ7OTHw/lcKn7xPNqeaqJyQbUO8/dJpvyTpaVwPsd3Uc33+CfNzdVowp2WA==", "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", + "browserslist": "^4.23.1", "caniuse-api": "^3.0.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-reduce-transforms": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", - "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.0.tgz", + "integrity": "sha512-pnt1HKKZ07/idH8cpATX/ujMbtOGhUfE+m8gbqwJE05aTaNw8gbo34a2e3if0xc0dlu75sUOiqvwCGY3fzOHew==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" @@ -1292,31 +1305,31 @@ } }, "node_modules/postcss-svgo": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", - "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-7.0.1.tgz", + "integrity": "sha512-0WBUlSL4lhD9rA5k1e5D8EN5wCEyZD6HJk0jIvRxl+FDVOMlJ7DePHYWGGVc5QRqrJ3/06FTXM0bxjmJpmTPSA==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", - "svgo": "^3.2.0" + "svgo": "^3.3.2" }, "engines": { - "node": "^14 || ^16 || >= 18" + "node": "^18.12.0 || ^20.9.0 || >= 18" }, "peerDependencies": { "postcss": "^8.4.31" } }, "node_modules/postcss-unique-selectors": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", - "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.1.tgz", + "integrity": "sha512-MH7QE/eKUftTB5ta40xcHLl7hkZjgDFydpfTK+QWXeHxghVt3VoPqYL5/G+zYZPPIs+8GuqFXSTgxBSoB1RZtQ==", "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.16" + "postcss-selector-parser": "^6.1.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" @@ -1366,16 +1379,16 @@ } }, "node_modules/stylehacks": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", - "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.2.tgz", + "integrity": "sha512-HdkWZS9b4gbgYTdMg4gJLmm7biAUug1qTqXjS+u8X+/pUd+9Px1E+520GnOW3rST9MNsVOVpsJG+mPHNosxjOQ==", "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", - "postcss-selector-parser": "^6.0.16" + "browserslist": "^4.23.1", + "postcss-selector-parser": "^6.1.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { "postcss": "^8.4.31" @@ -1416,9 +1429,9 @@ } }, "node_modules/terser": { - "version": "5.31.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz", - "integrity": "sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==", + "version": "5.31.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz", + "integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", diff --git a/package.json b/package.json index 88c219a..83e7da3 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,5 @@ { "dependencies": { - "@swc/core": "^1.5.24", - "autoprefixer": "^10.4.19", - "cssnano": "^6.1.2", - "html-minifier-terser": "^7.2.0", - "postcss": "^8.4.38" + "@railcomm/assproc": "^1.0.0" } } diff --git a/src/init.js/main.js b/src/init.js/main.js index 67ca06e..39de908 100644 --- a/src/init.js/main.js +++ b/src/init.js/main.js @@ -1,4 +1,4 @@ -#buildvars +#vars self build (function() { var isCompatible = (function() { diff --git a/src/mami.css/main_cont.css b/src/mami.css/main_cont.css index b685bed..3144960 100644 --- a/src/mami.css/main_cont.css +++ b/src/mami.css/main_cont.css @@ -6,7 +6,7 @@ flex-direction: column; } -@media (max-width:768px) { +@media (max-width: 800px) { .main { margin-right: 44px; } diff --git a/src/mami.css/setting.css b/src/mami.css/setting.css index 4acc208..5de3325 100644 --- a/src/mami.css/setting.css +++ b/src/mami.css/setting.css @@ -3,6 +3,10 @@ select { accent-color: currentcolor; } +.setting__category { + overflow: hidden; +} + .setting__category-title { font-size: 2em; line-height: 1.1em; @@ -11,6 +15,7 @@ select { position: sticky; top: 0; z-index: 1; + cursor: pointer; } .setting__container { @@ -60,3 +65,13 @@ select { .setting__container--button .setting__input[disabled] { opacity: .6; } + +.settings-warning { + font-size: .9em; + line-height: 1.4em; + margin: 5px; + padding: 5px; + background-color: darkred; + border: 2px solid red; + border-radius: 5px; +} diff --git a/src/mami.css/sidebar.css b/src/mami.css/sidebar.css index 101072f..b2fcf5e 100644 --- a/src/mami.css/sidebar.css +++ b/src/mami.css/sidebar.css @@ -6,7 +6,7 @@ box-shadow: var(--theme-size-sidebar-box-shadow-x, 0) var(--theme-size-sidebar-box-shadow-y, 0) var(--theme-size-sidebar-box-shadow-blur, 0) var(--theme-size-sidebar-box-shadow-spread, 0) var(--theme-colour-sidebar-box-shadow, #000); } -@media (max-width:768px) { +@media(max-width: 800px) { .sidebar { position: fixed; top: max(4px, env(safe-area-inset-top)); @@ -15,19 +15,8 @@ } } -.sidebar--closed { - min-width: 40px -} - -.sidebar--closed .sidebar__menus { - display: none -} - .sidebar__selector { order: 1; - font: 2em/40px "Font Awesome 5 Free"; - font-weight: 900; - text-align: center; display: flex; flex-direction: column; overflow: auto; @@ -43,9 +32,14 @@ } .sidebar__selector-mode { + color: inherit; height: 40px; width: 40px; cursor: pointer; + background: transparent; + border: 0; + border-radius: 0; + display: block; transition: background .1s, text-shadow .1s; } @@ -61,74 +55,10 @@ background-color: var(--theme-colour-sidebar-selector-background-active, #ddd) !important; } -.sidebar__selector-mode--hidden { - display: none; -} - .sidebar__selector-mode--attention { text-shadow: var(--theme-size-sidebar-selector-attention-shadow-x, 0) var(--theme-size-sidebar-selector-attention-shadow-y, 0) var(--theme-size-sidebar-selector-attention-shadow-blur, 0) var(--theme-colour-sidebar-selector-attention-shadow, #888); } -.sidebar__selector-mode--users:before { - content: "\f0c0" -} - -.sidebar__selector-mode--channels:before { - content: "\f292" -} - -.sidebar__selector-mode--settings:before { - content: "\f013" -} - -.sidebar__selector-mode--uploads:before { - content: "\f093" -} - -.sidebar__selector-mode--audio:before { - content: "\f028" -} - -.sidebar__selector-mode--audio-off:before { - content: "\f026" -} - -.sidebar__selector-mode--scroll:before { - content: "\f04e" -} - -.sidebar__selector-mode--scroll-off:before { - content: "\f04c" -} - -.sidebar__selector-mode--unembed:before { - font-weight: 400; - content: "\f146" -} - -.sidebar__selector-mode--clear { - background-image: url('//static.flash.moe/images/bomb.png'); -} -/*.sidebar__selector-mode--clear:before { - content: "\f2ed" -}*/ - -.sidebar__selector-mode--ping { - padding: 4px; -} -.sidebar__selector-mode--ping .ping { - width: 32px; - height: 32px; -} - -.sidebar__selector-mode--menu-toggle-opened:before { - content: "\f152" -} - -.sidebar__selector-mode--menu-toggle-closed:before { - content: "\f191" -} - .sidebar__menus { flex-grow: 1; flex-shrink: 1; @@ -137,14 +67,6 @@ scrollbar-width: thin; } -.sidebar__menu { - display: none; -} - -.sidebar__menu--active { - display: inline; -} - .sidebar__user, .sidebar__channel { display: flex; @@ -177,10 +99,6 @@ overflow: hidden; } -.sidebar__user-options--hidden { - display: none -} - .sidebar__user-option { padding: 2px 5px; cursor: pointer; @@ -206,3 +124,12 @@ float: right; line-height: 1.4em; } + +.sidebar-gutter-font-icon { + font-size: 1.5rem; + line-height: 40px; +} + +.sidebar-gutter-element { + margin: 4px; +} diff --git a/src/mami.js/channels.js b/src/mami.js/channels.js deleted file mode 100644 index f3c7056..0000000 --- a/src/mami.js/channels.js +++ /dev/null @@ -1,104 +0,0 @@ -const MamiChannelInfo = function(name, hasPassword = false, isTemporary = true, isUserChannel = false) { - if(typeof name !== 'string') - throw 'name must be a string'; - if(typeof hasPassword !== 'boolean') - throw 'hasPassword must be a boolean'; - if(typeof isTemporary !== 'boolean') - throw 'isTemporary must be a boolean'; - if(typeof isUserChannel !== 'boolean') - throw 'isUserChannel must be a boolean'; - - return { - get name() { return name; }, - set name(value) { - if(typeof value !== 'string') - throw 'value must be a string'; - name = value; - }, - - get hasPassword() { return hasPassword; }, - set hasPassword(value) { - if(typeof value !== 'boolean') - throw 'value must be a boolean'; - hasPassword = value; - }, - - get isTemporary() { return isTemporary; }, - set isTemporary(value) { - if(typeof value !== 'boolean') - throw 'value must be a boolean'; - isTemporary = value; - }, - - get isUserChannel() { return isUserChannel; }, - }; -}; - -Umi.Channels = (function() { - const chans = new Map; - let currentName = null; - - const onAdd = []; - const onRemove = []; - const onClear = []; - const onUpdate = []; - const onSwitch = []; - - return { - OnAdd: onAdd, - OnRemove: onRemove, - OnClear: onClear, - OnUpdate: onUpdate, - OnSwitch: onSwitch, - Add: function(channel) { - const channelName = channel.name; - if(!chans.has(channelName)) { - chans.set(channelName, channel); - - for(const i in onAdd) - onAdd[i](channel); - } - }, - Remove: function(channel) { - const channelName = channel.name; - if(chans.has(channelName)) { - chans.delete(channelName); - - for(const i in onRemove) - onRemove[i](channel); - } - }, - Clear: function() { - chans.clear(); - - for(const i in onClear) - onClear[i](); - }, - All: function() { - return Array.from(chans.values()); - }, - Get: function(channelName) { - channelName = channelName.toString(); - if(chans.has(channelName)) - return chans.get(channelName); - return null; - }, - Update: function(channelName, channel) { - channelName = channelName.toString(); - chans.set(channelName, channel); - - for(const i in onUpdate) - onUpdate[i](name, channel); - }, - Current: function() { - return currentName; - }, - Switch: function(channelName) { - const old = currentName; - currentName = channelName; - - for(const i in onSwitch) - onSwitch[i](old, channelName); - }, - }; -})(); diff --git a/src/mami.js/controls/msgbox.jsx b/src/mami.js/controls/msgbox.jsx index 7865492..b0153c4 100644 --- a/src/mami.js/controls/msgbox.jsx +++ b/src/mami.js/controls/msgbox.jsx @@ -106,9 +106,9 @@ const MamiMessageBoxDialog = function(info) { if(info.body !== undefined) { if(Array.isArray(info.body)) for(const line of info.body) - body.appendChild(
{line}
); + body.appendChild({line.toString()}
); else - body.appendChild({info.body}
); + body.appendChild({info.body.toString()}
); } const buttons = ; diff --git a/src/mami.js/main.js b/src/mami.js/main.js index 625ab22..adc1a10 100644 --- a/src/mami.js/main.js +++ b/src/mami.js/main.js @@ -1,6 +1,7 @@ window.Umi = { UI: {} }; #include animate.js +#include awaitable.js #include common.js #include compat.js #include conman.js @@ -10,6 +11,7 @@ window.Umi = { UI: {} }; #include mobile.js #include mszauth.js #include txtrigs.js +#include users.js #include utility.js #include weeb.js #include worker.js @@ -19,22 +21,32 @@ window.Umi = { UI: {} }; #include eeprom/eeprom.js #include settings/backup.js #include settings/settings.js +#include sidebar/act-clear-backlog.jsx +#include sidebar/act-collapse-all.jsx +#include sidebar/act-ping.jsx +#include sidebar/act-scroll.jsx +#include sidebar/act-sound.jsx +#include sidebar/act-toggle.jsx +#include sidebar/pan-channels.jsx +#include sidebar/pan-settings.jsx +#include sidebar/pan-uploads.jsx +#include sidebar/pan-users.jsx +#include sidebar/sidebar.jsx #include sockchat/client.js #include sockchat/handlers.js #include sound/context.js #include sound/osukeys.js +#include sound/sndtest.jsx +#include ui/baka.jsx #include ui/chat-layout.js +#include ui/emotes.js #include ui/hooks.js #include ui/input-menus.js #include ui/loading-overlay.jsx #include ui/markup.js -#include ui/menus.js -#include ui/messages.jsx #include ui/ping.jsx -#include ui/settings.jsx -#include ui/toggles.js -#include ui/uploads.js #include ui/view.js +#include ui/youare.jsx (async () => { const eventTarget = new MamiEventTargetWindow; @@ -88,7 +100,6 @@ window.Umi = { UI: {} }; settings.define('compactView').default(false).create(); settings.define('autoScroll').default(true).create(); settings.define('closeTabConfirm').default(false).create(); - settings.define('showChannelList').default(false).create(); settings.define('autoCloseUserContext').default(true).create(); settings.define('preventOverflow').default(false).create(); settings.define('expandTextBox').default(false).create(); @@ -230,8 +241,41 @@ window.Umi = { UI: {} }; ctx.textTriggers = new MamiTextTriggers; - // should be dynamic when possible - const layout = new Umi.UI.ChatLayout; + const sidebar = new MamiSidebar; + + MamiCompat('Umi.UI.Menus.Add', { + value: (baseId, title) => { + sidebar.createPanel({ + name: `compat:${baseId}`, + text: title, + createdButton: button => { + button.element.id = `umi-menu-icons-${baseId}`; + button.element.append($e({ + attrs: { className: `sidebar__selector-mode--${baseId}` }, + })); + }, + element: $e({ + attrs: { 'class': `sidebar__menu--${baseId}`, id: `umi-menus-${baseId}` } + }), + }); + } + }); + MamiCompat('Umi.UI.Menus.Get', { + value: (baseId, icon) => { + const info = sidebar[icon ? 'getButton' : 'getPanel'](`compat:${baseId}`); + if(info === undefined) + return null; + + return icon ? info.element : info.element.firstElementChild; + }, + }); + MamiCompat('Umi.UI.Menus.Attention', { + value: baseId => { + sidebar.getButton(`compat:${baseId}`)?.attention(); + }, + }); + + const layout = new Umi.UI.ChatLayout(sidebar); await ctx.views.unshift(layout); Umi.UI.View.AccentReload(); @@ -299,115 +343,294 @@ window.Umi = { UI: {} }; MamiCompat('Umi.Parser.SockChatBBcode.EmbedStub', { value: () => {} }); // intentionally a no-op MamiCompat('Umi.UI.View.SetText', { value: text => console.log(`Umi.UI.View.SetText(text: ${text})`) }); - MamiCompat('Umi.UI.Menus.Add', { value: (baseId, title, initiallyHidden) => console.log(`Umi.UI.Menus.Add(baseId: ${baseId}, title: ${title}, initiallyHidden: ${initiallyHidden})`) }); - MamiCompat('Umi.UI.Menus.Get', { value: (baseId, icon) => console.log(`Umi.UI.Menus.Get(baseId: ${baseId}, icon: ${icon})`) }); - Umi.UI.Menus.Add('users', 'Users'); - Umi.UI.Menus.Add('channels', 'Channels', !settings.get('showChannelList')); - Umi.UI.Menus.Add('settings', 'Settings'); + const sbUsers = new MamiSidebarPanelUsers; + sidebar.createPanel(sbUsers); - let sidebarAnimation = null; - - Umi.UI.Settings.Init(); - Umi.UI.Toggles.Add('menu-toggle', { - 'click': function() { - const sidebar = $c('sidebar')[0]; - const toggle = Umi.UI.Toggles.Get('menu-toggle'); - const isClosed = toggle.classList.contains('sidebar__selector-mode--menu-toggle-closed'); - - if(sidebarAnimation !== null) { - sidebarAnimation.cancel(); - sidebarAnimation = null; - } - - toggle.classList.toggle('sidebar__selector-mode--menu-toggle-opened', isClosed); - toggle.classList.toggle('sidebar__selector-mode--menu-toggle-closed', !isClosed); - - let update; - if(isClosed) - update = function(t) { - sidebar.style.width = (40 + (220 * t)).toString() + 'px'; - }; - else - update = function(t) { - sidebar.style.width = (260 - (220 * t)).toString() + 'px'; - }; - - sidebarAnimation = MamiAnimate({ - duration: 500, - easing: 'outExpo', - update: update, - }); - } - }, 'Toggle Sidebar'); - - Umi.UI.Toggles.Get('menu-toggle').classList.add('sidebar__selector-mode--menu-toggle-opened'); - - Umi.UI.Toggles.Add('scroll', { - 'click': function() { - settings.toggle('autoScroll'); - } - }, 'Autoscroll'); - settings.watch('autoScroll', ev => { - Umi.UI.Toggles.Get('scroll').classList.toggle('sidebar__selector-mode--scroll-off', !ev.detail.value); + sbUsers.addOption({ + name: 'profile', + text: 'View profile', + onclick: entry => window.open(futami.get('profile').replace('{user:id}', entry.id), '_blank'), }); - - if(window.innerWidth < 768) - Umi.UI.Toggles.Get('menu-toggle').click(); - - Umi.UI.Toggles.Add('audio', { - 'click': function() { - settings.toggle('soundEnable'); - } - }, 'Sounds'); - settings.watch('soundEnable', ev => { - Umi.UI.Toggles.Get('audio').classList.toggle('sidebar__selector-mode--audio-off', !ev.detail.value); + sbUsers.addOption({ + name: 'action', + text: 'Describe action', + condition: entry => Umi.User.getCurrentUser()?.id === entry.id, + onclick: entry => { Umi.UI.View.SetText('/me '); }, }); - - Umi.UI.Toggles.Add('unembed', { - 'click': function() { - const buttons = $qa('[data-embed="1"]'); - for(const button of buttons) - button.click(); - } - }, 'Collapse any expanded elements'); - - Umi.UI.Toggles.Add('clear', { - 'click': function() { - ctx.msgbox.show({ body: 'ARE YOU SURE ABOUT THAT???', yes: true, no: true }).then(() => { - const explode = $e({ - tag: 'img', - attrs: { - src: '//static.flash.moe/images/explode.gif', - alt: '', - style: { - position: 'absolute', - zIndex: 9001, - bottom: 0, - right: 0, - pointerEvents: 'none', - }, - onLoad: function() { - setTimeout(function() { - $r(explode); - }, 1700); - - soundCtx.library.play('misc:explode'); - }, - }, + sbUsers.addOption({ + name: 'nick', + text: 'Set nickname', + condition: entry => Umi.User.getCurrentUser()?.id === entry.id && Umi.User.getCurrentUser().perms.canSetNick, + onclick: entry => { Umi.UI.View.SetText('/nick '); }, + }); + sbUsers.addOption({ + name: 'bans', + text: 'View bans', + condition: entry => Umi.User.getCurrentUser()?.id === entry.id && Umi.User.getCurrentUser().perms.canKick, + onclick: entry => { Umi.Server.sendMessage('/bans'); }, + }); + sbUsers.addOption({ + name: 'kfe', + text: 'Kick Fucking Everyone', + condition: entry => Umi.User.getCurrentUser()?.id === entry.id && Umi.User.getCurrentUser().perms.canKick, + onclick: async entry => { + try { + await ctx.msgbox.show({ + body: ['You are about to detonate the fucking bomb.', 'Are you sure?'], + yes: { text: 'FUCK IT, WE BALL' }, + no: { text: 'nah' }, }); - document.body.appendChild(explode); - Umi.UI.Messages.Clear(settings.get('explosionRadius')); - }).catch(() => {}); - } - }, 'Clear Logs'); + const names = sbUsers.getAllUserNames(); + for(const name of names) + if(Umi.User.getCurrentUser()?.name !== name) + // this shouldn't call it like this but will have to leave it for now + Umi.Server.sendMessage(`/kick ${name}`); + } catch(ex) {} + }, + }); + sbUsers.addOption({ + name: 'dm', + text: 'Send direct message', + condition: entry => Umi.User.getCurrentUser()?.id !== entry.id, + onclick: entry => { Umi.UI.View.SetText(`/msg ${entry.name} `); }, + }); + sbUsers.addOption({ + name: 'kick', + text: 'Kick from chat', + condition: entry => Umi.User.hasCurrentUser() && Umi.User.getCurrentUser().id !== entry.id && Umi.User.getCurrentUser().perms.canKick, + onclick: entry => { Umi.UI.View.SetText(`/kick ${entry.name} `); }, + }); + sbUsers.addOption({ + name: 'ipaddr', + text: 'View IP address', + condition: entry => Umi.User.hasCurrentUser() && Umi.User.getCurrentUser().id !== entry.id && Umi.User.getCurrentUser().perms.canKick, + onclick: entry => { Umi.Server.sendMessage(`/ip ${entry.name}`); }, + }); + + + const sbChannels = new MamiSidebarPanelChannels; + sidebar.createPanel(sbChannels); + + + const sbSettings = new MamiSidebarPanelSettings(settings); + sidebar.createPanel(sbSettings); + + sbSettings.category(category => { + category.header('Interface'); + category.setting('style').title('Style').type('select').options(() => Umi.UI.View.AccentColours).done(); + category.setting('compactView').title('Use compact view').done(); + category.setting('autoScroll').title('Enable auto scroll').done(); + category.setting('closeTabConfirm').title('Confirm tab close').done(); + category.setting('autoCloseUserContext').title('Auto-close user menus').done(); + }); + sbSettings.category(category => { + category.header('Text'); + category.setting('preventOverflow').title('Prevent overflow').done(); + category.setting('expandTextBox').title('Grow input box while typing').done(); + category.setting('eepromAutoInsert').title('Auto-insert uploads').done(); + category.setting('autoEmbedV1').title('Auto-embed media').done(); + category.setting('autoEmbedPlay').title('Auto-play embedded media').done(); + }); + sbSettings.category(category => { + category.header('Notifications'); + category.setting('flashTitle').title('Strobe title on new message').done(); + category.setting('enableNotifications').title('Show notifications').done(); + category.setting('notificationShowMessage').title('Show contents of message').done(); + category.setting('notificationTriggers').title('Triggers').done(); + }); + sbSettings.category(category => { + category.header('Sound'); + category.setting('soundEnable').title('Enable sound').done(); + category.setting('soundPack').title('Sound pack').type('select').options(() => { + const options = { '': 'Default' }; + + for(const name of soundCtx.packs.names()) + options[name] = soundCtx.packs.info(name).getTitle(); + + return options; + }).done(); + category.setting('soundVolume').title('Sound volume').type('range').done(); + category.setting('soundEnableJoin').title('Play join sound').done(); + category.setting('soundEnableLeave').title('Play leave sound').done(); + category.setting('soundEnableError').title('Play error sound').done(); + category.setting('soundEnableServer').title('Play server message sound').done(); + category.setting('soundEnableIncoming').title('Play receive message sound').done(); + category.setting('onlySoundOnMention').title('Only plays sounds when you are mentioned').done(); + category.setting('soundEnableOutgoing').title('Play send message sound').done(); + category.setting('soundEnablePrivate').title('Play private message sound').done(); + category.setting('soundEnableForceLeave').title('Play kick sound').done(); + category.setting('minecraft').title('Minecraft').type('select').options(() => { + return { + 'no': 'No Minecraft', + 'yes': 'Yes Minecraft', + 'old': 'Old Minecraft', + }; + }).done(); + category.setting('windowsLiveMessenger').title('Windows Live Messenger').done(); + category.setting('seinfeld').title('Seinfeld').done(); + }); + sbSettings.category(category => { + category.header('Misc'); + category.setting('onlyConnectWhenVisible2').title('Only connect when the tab is in the foreground').confirm([ + 'Please only disable this setting if you are using a desktop or laptop computer, this should always remain on on a phone, tablet or other device of that sort.', + 'Are you sure you want to change this setting? Ignoring this warning may carry consequences.', + ]).done(); + category.setting('playJokeSounds').title('Run joke triggers').done(); + category.setting('weeaboo').title('Weeaboo').done(); + category.setting('motivationalImages').title('Make images motivational').done(); + category.setting('motivationalVideos').title('Make videos motivational').done(); + category.setting('osuKeysV2').title('osu! keyboard sounds').type('select').options(() => { + return { + 'no': 'Off', + 'yes': 'On', + 'rng': 'On, random pitch', + }; + }).done(); + category.setting('explosionRadius').title('Messages to keep on clear').done(); + }); + sbSettings.category(category => { + category.header('Actions'); + category.button('Open compatibility client', () => { window.open(window.AMI_URL, '_blank', 'noopener'); }); + category.button('Manual reconnect', async button => { + const textOrig = button.textContent; + let lock = 10; + + button.disabled = true; + button.textContent = 'Reconnecting...'; + try { + await ctx.conMan.start(); + + while(--lock > 0) { + button.textContent = textOrig + ` (${lock}s)`; + await MamiSleep(1000); + } + } finally { + button.textContent = textOrig; + button.disabled = false; + } + }); + category.button('Reload emoticons', async button => { + const textOrig = button.textContent; + + button.disabled = true; + button.textContent = 'Reloading emoticons...'; + try { + const emotes = await futami.getJson('emotes', true); + MamiEmotes.clear(); + MamiEmotes.loadLegacy(emotes); + } finally { + Umi.UI.Emoticons.Init(); + button.textContent = textOrig; + button.disabled = false; + } + }); + category.button('Reload sound library', async button => { + const textOrig = button.textContent; + + button.disabled = true; + button.textContent = 'Reloading sound library...'; + try { + const sounds = await futami.getJson('sounds2'); + if(Array.isArray(sounds.library)) + soundCtx.library.register(sounds.library, true); + + if(Array.isArray(sounds.packs)) { + soundCtx.packs.register(sounds.packs, true); + settings.touch('soundPack', true); + } + } finally { + button.textContent = textOrig; + button.disabled = false; + } + }); + category.button('Reload joke triggers', async button => { + const textOrig = button.textContent; + + button.disabled = true; + button.textContent = 'Reloading joke triggers...'; + try { + const triggers = await futami.getJson('texttriggers', true); + ctx.textTriggers.clearTriggers(); + ctx.textTriggers.addTriggers(triggers) + } finally { + button.textContent = textOrig; + button.disabled = false; + } + }); + }); + sbSettings.category(category => { + category.header('Settings'); + category.button('Import settings', () => { + (new MamiSettingsBackup(settings)).importUpload(document.body); + }, ['Your current settings will be replaced with the ones in the export.', 'Are you sure you want to continue?']); + category.button('Export settings', () => { + const user = Umi.User.getCurrentUser(); + let fileName; + if(user !== null) + fileName = `${user.name}'s settings.mami`; + + (new MamiSettingsBackup(settings)).exportDownload(document.body, fileName); + }); + category.button('Reset settings', () => { + settings.clear(); + }, ['This will reset all your settings to their defaults values.', 'Are you sure you want to do this?']); + }); + sbSettings.category(category => { + category.header('Debug'); + category.collapse(); + category.warning("Only touch these settings if you're ABSOLUTELY sure you know what you're doing, you're on your own if you break something."); + category.setting('dumpPackets').title('Dump packets to console').done(); + category.setting('dumpEvents').title('Dump events to console').done(); + category.setting('marqueeAllNames').title('Apply marquee on everyone').done(); + category.setting('tmpDisableOldThemeSys').title('Disable old theme system').done(); + category.setting('dbgAnimDurationMulti').title('Animation multiplier').type('range').done(); + category.button('Test kick/ban notice', async button => { + button.disabled = true; + await ctx.views.push(new MamiForceDisconnectNotice({ perma: true, type: 'ban' })); + await MamiSleep(5000); + await ctx.views.pop(); + button.disabled = false; + }); + category.button('You are an idiot!', async button => { + button.disabled = true; + await ctx.views.push(new MamiYouAreAnIdiot(soundCtx.library, ctx.views)); + button.disabled = false; + }); + category.button('Sound test', async (button, ev) => { + button.disabled = true; + await ctx.views.push(new MamiSoundTest( + settings, + soundCtx.audio, + soundCtx.manager, + soundCtx.library, + [ev.clientX, ev.clientY], + )); + button.disabled = false; + }); + category.button('Reset audio context', () => { + soundCtx.reset(); + }); + }); + + + const sbUploads = new MamiSidebarPanelUploads; + sidebar.createPanel(sbUploads); + + const sbActToggle = new MamiSidebarActionToggle(sidebar); + sidebar.createAction(sbActToggle); + if(window.innerWidth < 800) + sbActToggle.click(); + + sidebar.createAction(new MamiSidebarActionScroll(settings)); + sidebar.createAction(new MamiSidebarActionSound(settings)); + sidebar.createAction(new MamiSidebarActionCollapseAll); + sidebar.createAction(new MamiSidebarActionClearBacklog(settings, soundCtx.library, ctx.msgbox)); const pingIndicator = new MamiPingIndicator; - const pingToggle = Umi.UI.Toggles.Add('ping', { - click: () => { ctx.msgbox.show({ body: `Your current ping is ${pingToggle.title}` }); }, - }, 'Ready~'); - pingToggle.appendChild(pingIndicator.getElement()); + const sbActPing = new MamiSidebarActionPing(pingIndicator, ctx.msgbox); + sidebar.createAction(sbActPing); Umi.UI.InputMenus.Add('markup', 'BB Code'); Umi.UI.InputMenus.Add('emotes', 'Emoticons'); @@ -415,60 +638,80 @@ window.Umi = { UI: {} }; let doUpload; ctx.eeprom = new MamiEEPROM(futami.get('eeprom2'), MamiMisuzuAuth.getLine); ctx.eeprom.init() - .catch(ex => { - console.log('Failed to initialise EEPROM.', ex); - }) + .catch(ex => { console.error('Failed to initialise EEPROM.', ex); }) .then(() => { - Umi.UI.Menus.Add('uploads', 'Upload History', !FUTAMI_DEBUG); + sbUploads.addOption({ + name: 'view', + text: 'View upload', + condition: entry => entry.uploadInfo !== undefined, + onclick: entry => window.open(entry.uploadInfo.url), + }); + sbUploads.addOption({ + name: 'insert', + text: 'Insert into message', + condition: entry => entry.uploadInfo !== undefined, + onclick: entry => { + const upload = entry.uploadInfo; + + let text; + if(upload.isImage()) { + text = `[img]${upload.url}[/img]`; + } else if(upload.isAudio()) { + text = `[audio]${upload.url}[/audio]`; + } else if(upload.isVideo()) { + text = `[video]${upload.url}[/video]`; + } else + text = location.protocol + upload.url; + + Umi.UI.Markup.InsertRaw(text, '') + }, + }); + sbUploads.addOption({ + name: 'delete', + text: 'Delete upload', + condition: entry => entry.uploadInfo !== undefined, + onclick: async entry => { + try { + await ctx.eeprom.delete(entry.uploadInfo); + sbUploads.deleteEntry(entry); + } catch(ex) { + console.error(ex); + await ctx.msgbox.show({ body: ['An error occurred while trying to delete an uploaded file:', ex] }); + } + }, + }); doUpload = async file => { - const uploadEntry = Umi.UI.Uploads.create(file.name); - const uploadTask = ctx.eeprom.create(file); + const entry = sbUploads.createEntry(file); - uploadTask.onProgress(prog => uploadEntry.setProgress(prog.progress)); - uploadEntry.addOption('Cancel', () => uploadTask.abort()); + const task = ctx.eeprom.create(file); + task.onProgress(prog => { + entry.progress = prog.progress; + }); + entry.addOption({ + name: 'cancel', + text: 'Cancel upload', + onclick: () => { task.abort(); }, + }); try { - const fileInfo = await uploadTask.start(); + const fileInfo = await task.start(); - uploadEntry.hideOptions(); - uploadEntry.clearOptions(); - uploadEntry.removeProgress(); - - uploadEntry.addOption('Open', fileInfo.url); - uploadEntry.addOption('Insert', () => Umi.UI.Markup.InsertRaw(insertText, '')); - uploadEntry.addOption('Delete', () => { - ctx.eeprom.delete(fileInfo) - .then(() => uploadEntry.remove()) - .catch(ex => { - console.error(ex); - ctx.msgbox.show({ body: ['An error occurred while trying to delete an uploaded file:', ex] }); - }); - }); - - let insertText; - - if(fileInfo.isImage()) { - insertText = `[img]${fileInfo.url}[/img]`; - uploadEntry.setThumbnail(fileInfo.thumb); - } else if(fileInfo.isAudio()) { - insertText = `[audio]${fileInfo.url}[/audio]`; - uploadEntry.setThumbnail(fileInfo.thumb); - } else if(fileInfo.isVideo()) { - insertText = `[video]${fileInfo.url}[/video]`; - uploadEntry.setThumbnail(fileInfo.thumb); - } else - insertText = location.protocol + fileInfo.url; + entry.optionsVisible = false; + entry.uploadInfo = fileInfo; + entry.removeOption('cancel'); + entry.nukeProgress(); + sbUploads.reloadOptionsFor(entry); if(settings.get('eepromAutoInsert')) - Umi.UI.Markup.InsertRaw(insertText, ''); + entry.clickOption('insert'); } catch(ex) { if(!ex.aborted) { console.error(ex); ctx.msgbox.show({ body: ['An error occurred while trying to upload a file:', ex] }); } - uploadEntry.remove(); + sbUploads.deleteEntry(entry); } }; @@ -562,13 +805,23 @@ window.Umi = { UI: {} }; const conMan = new MamiConnectionManager(sockChat, settings, futami.get('servers'), ctx.events.scopeTo('conn')); ctx.conMan = conMan; + sbChannels.onClickEntry = async info => { + await sockChat.client.switchChannel(info); + + // hack for DM channels + if(info.isUserChannel) { + sbChannels.setActiveEntry(info.name); + Umi.UI.Messages.SwitchChannel(info); + } + }; + let sockChatRestarting; const sockChatReconnect = () => { if(conMan.isActive) return; - pingToggle.title = 'Reconnecting...'; + sbActPing.pingMs = -1; pingIndicator.setStrength(-1); const reconManAttempt = ev => { @@ -593,7 +846,10 @@ window.Umi = { UI: {} }; conMan.start(); }; - const sockChatHandlers = new MamiSockChatHandlers(ctx, sockChat, setLoadingOverlay, sockChatReconnect, pingIndicator, pingToggle); + const sockChatHandlers = new MamiSockChatHandlers( + ctx, sockChat, setLoadingOverlay, sockChatReconnect, pingIndicator, + sbActPing, sbChannels, sbUsers + ); settings.watch('dumpEvents', ev => sockChatHandlers.setDumpEvents(ev.detail.value)); settings.watch('dumpPackets', ev => sockChat.setDumpPackets(ev.detail.value)); sockChatHandlers.register(); diff --git a/src/mami.js/sidebar/act-clear-backlog.jsx b/src/mami.js/sidebar/act-clear-backlog.jsx new file mode 100644 index 0000000..3f2c824 --- /dev/null +++ b/src/mami.js/sidebar/act-clear-backlog.jsx @@ -0,0 +1,30 @@ +#include awaitable.js +#include ui/messages.jsx + +const MamiSidebarActionClearBacklog = function(settings, sndLib, msgBox) { + return { + get name() { return 'act:clear-backlog'; }, + get text() { return 'Clear backlog'; }, + + createdButton: button => { + button.element.append(); + }, + + onclick: async () => { + try { + await msgBox.show({ body: 'ARE YOU SURE ABOUT THAT???', yes: true, no: true }); + + const explode = ; + document.body.appendChild(explode); + + sndLib.play('misc:explode'); + + Umi.UI.Messages.Clear(settings.get('explosionRadius')); + + await MamiSleep(1700); + explode.remove(); + } catch(ex) {} + }, + }; +}; diff --git a/src/mami.js/sidebar/act-collapse-all.jsx b/src/mami.js/sidebar/act-collapse-all.jsx new file mode 100644 index 0000000..a030d52 --- /dev/null +++ b/src/mami.js/sidebar/act-collapse-all.jsx @@ -0,0 +1,20 @@ +#include utility.js + +const MamiSidebarActionCollapseAll = function() { + // this should take a reference to the message container rather than just using $qa + + return { + get name() { return 'act:collapse-all'; }, + get text() { return 'Collapse any expanded elements'; }, + + createdButton: button => { + button.element.append(); + }, + + onclick: () => { + const buttons = $qa('[data-embed="1"]'); + for(const button of buttons) + button.click(); + }, + }; +}; diff --git a/src/mami.js/sidebar/act-ping.jsx b/src/mami.js/sidebar/act-ping.jsx new file mode 100644 index 0000000..0d6fd4f --- /dev/null +++ b/src/mami.js/sidebar/act-ping.jsx @@ -0,0 +1,43 @@ +#include awaitable.js +#include ui/messages.jsx + +const MamiSidebarActionPing = function(pingIndicator, msgBox) { + let text, buttonElem, pingMs; + + const updateText = () => { + if(pingMs === undefined) + text = 'Ready~'; + else if(pingMs < 0) + text = 'Reconnecting...'; + else + text = `${pingMs}ms`; + + if(buttonElem !== undefined) + buttonElem.title = text; + }; + + updateText(); + + return { + get name() { return 'act:ping'; }, + get text() { return text; }, + + get pingMs() { return pingMs; }, + set pingMs(value) { + pingMs = value; + updateText(); + }, + + createdButton: button => { + buttonElem = button.element; + updateText(); + buttonElem.append( ); + }, + + onclick: async () => { + await msgBox.show({ + body: pingMs < 0 ? 'Reconnecting...' : `Your current ping is ${pingMs}ms.` + }); + }, + }; +}; diff --git a/src/mami.js/sidebar/act-scroll.jsx b/src/mami.js/sidebar/act-scroll.jsx new file mode 100644 index 0000000..96703b1 --- /dev/null +++ b/src/mami.js/sidebar/act-scroll.jsx @@ -0,0 +1,22 @@ +const MamiSidebarActionScroll = function(settings) { + const scrollOn = ; + const scrollOff = ; + + settings.watch('autoScroll', ev => { + scrollOn.classList.toggle('hidden', !ev.detail.value); + scrollOff.classList.toggle('hidden', ev.detail.value); + }); + + return { + get name() { return 'act:scroll'; }, + get text() { return 'Auto scroll'; }, + + createdButton: button => { + button.element.append(scrollOn, scrollOff); + }, + + onclick: () => { + settings.toggle('autoScroll'); + }, + }; +}; diff --git a/src/mami.js/sidebar/act-sound.jsx b/src/mami.js/sidebar/act-sound.jsx new file mode 100644 index 0000000..8e9928e --- /dev/null +++ b/src/mami.js/sidebar/act-sound.jsx @@ -0,0 +1,22 @@ +const MamiSidebarActionSound = function(settings) { + const soundOn = ; + const soundOff = ; + + settings.watch('soundEnable', ev => { + soundOn.classList.toggle('hidden', !ev.detail.value); + soundOff.classList.toggle('hidden', ev.detail.value); + }); + + return { + get name() { return 'act:sound'; }, + get text() { return 'Sounds'; }, + + createdButton: button => { + button.element.append(soundOn, soundOff); + }, + + onclick: () => { + settings.toggle('soundEnable'); + }, + }; +}; diff --git a/src/mami.js/sidebar/act-toggle.jsx b/src/mami.js/sidebar/act-toggle.jsx new file mode 100644 index 0000000..d649220 --- /dev/null +++ b/src/mami.js/sidebar/act-toggle.jsx @@ -0,0 +1,33 @@ +#include animate.js + +const MamiSidebarActionToggle = function(sidebar) { + const toggleClose = ; + const toggleOpen = ; + + let buttonElem; + + sidebar.frame.watch('mami:sidebar:toggle', ev => { + toggleClose.classList.toggle('hidden', !ev.detail.open); + toggleOpen.classList.toggle('hidden', ev.detail.open); + }); + + return { + get name() { return 'act:toggle'; }, + get text() { return 'Toggle sidebar'; }, + + click: () => { + buttonElem?.click(); + }, + + createdButton: button => { + buttonElem = button.element; + buttonElem.append(toggleClose, toggleOpen); + }, + + onclick: async () => { + try { + await sidebar.toggle(); + } catch(ex) {} + }, + }; +}; diff --git a/src/mami.js/sidebar/pan-channels.jsx b/src/mami.js/sidebar/pan-channels.jsx new file mode 100644 index 0000000..05d153c --- /dev/null +++ b/src/mami.js/sidebar/pan-channels.jsx @@ -0,0 +1,126 @@ +const MamiSidebarPanelChannelsEntry = function(info) { + const nameElem = ; + const html = ; + + let clickHandler; + html.addEventListener('click', ev => { + if(typeof clickHandler === 'function') + clickHandler(info, html, ev); + }); + + return { + get element() { return html; }, + + get name() { return html.dataset.channelName; }, + set name(value) { + if(typeof value !== 'string') + throw 'value must be a string'; + + html.dataset.channelName = value; + nameElem.textContent = value; + }, + + get active() { return html.classList.contains('sidebar__channel--current'); }, + set active(value) { + html.classList.toggle('sidebar__channel--current', value); + if(value) + html.classList.remove('sidebar__channel--unread'); + }, + + get unread() { return html.classList.contains('sidebar__channel--unread'); }, + set unread(value) { + if(!html.classList.contains('sidebar__channel--current')) + html.classList.toggle('sidebar__channel--unread', value); + }, + + set onclick(handler) { + clickHandler = handler; + }, + + click: () => { html.click(); }, + }; +}; + +const MamiSidebarPanelChannels = function() { + const html = ; + const entries = new Map; + let sbButton; + + let clickHandler; + const invokeClick = (...args) => { + if(typeof clickHandler === 'function') + clickHandler(...args); + }; + + return { + get name() { return 'pan:channels'; }, + get text() { return 'Channels'; }, + + get element() { return html; }, + + set onClickEntry(handler) { + clickHandler = handler; + }, + + createdButton: button => { + sbButton = button; + sbButton.element.append(); + }, + + createEntry: info => { + if(entries.has(info.name)) + throw 'a channel with this name has already been inserted'; + + const entry = new MamiSidebarPanelChannelsEntry(info); + entry.onclick = invokeClick; + if(info.isCurrent) + entry.active = true; + + html.appendChild(entry.element); + entries.set(info.name, entry); + }, + deleteEntry: name => { + const entry = entries.get(name); + if(entry === undefined) + return; + + entries.delete(entry.name); + html.removeChild(entry.element); + }, + updateEntry: (name, info) => { + const entry = entries.get(name); + if(entry === undefined) + return; + + if(info.name !== undefined && entry.name !== info.name) { + entries.delete(entry.name); + entry.name = info.name; + entries.set(entry.name, entry); + } + }, + hasEntry: name => entries.has(name), + clearEntries: () => { + for(const [name, entry] of entries) { + entries.delete(name); + html.removeChild(entry.element); + } + }, + setActiveEntry: name => { + for(const entry of entries.values()) + entry.active = entry.name === name; + }, + setUnreadEntry: name => { + const entry = entries.get(name); + if(entry !== undefined) { + entry.unread = true; + + if(sbButton !== undefined && entry.unread) + sbButton.attention(); + } + }, + }; +}; diff --git a/src/mami.js/sidebar/pan-settings.jsx b/src/mami.js/sidebar/pan-settings.jsx new file mode 100644 index 0000000..4b7692c --- /dev/null +++ b/src/mami.js/sidebar/pan-settings.jsx @@ -0,0 +1,248 @@ +const MamiSidebarPanelSettings = function(settings, msgBox) { + const copyright = ; + + const html = ; + + return { + get name() { return 'pan:settings'; }, + get text() { return 'Settings'; }, + + get element() { return html; }, + + createdButton: button => { + button.element.append(); + }, + + category: categoryHandler => { + const header = ; + const body = ; + const category =