diff --git a/bin.mjs b/bin.mjs index ad32701..afe5e74 100755 --- a/bin.mjs +++ b/bin.mjs @@ -141,8 +141,10 @@ const printHelp = (commands, options) => { } else { const cmdPad = Math.max(...commands.map(([cmd]) => cmd.length)), optPad = Math.max(...options.map((opt) => opt[0].length)), - parseCmd = (cmd) => chalk` ${cmd[0].padEnd(cmdPad)} {grey :} ${cmd[1]}`, - parseOpt = (opt) => chalk` ${opt[0].padEnd(optPad)} {grey :} ${opt[1][1]}`; + parseCmd = (cmd) => + chalk` ${cmd[0].padEnd(cmdPad)} {grey :} ${cmd[1]}`, + parseOpt = (opt) => + chalk` ${opt[0].padEnd(optPad)} {grey :} ${opt[1][1]}`; print`{bold.whiteBright ${name} v${version}}\n{grey ${homepage}} \n{bold.whiteBright USAGE}\n${name} [options] \n{bold.whiteBright COMMANDS}\n${commands.map(parseCmd).join("\n")} @@ -179,11 +181,26 @@ try { "--path=", [String, "manually provide a notion installation location"], ], - ["--overwrite", [Boolean, "for rapid development; unsafely overwrite sources"]], - ["--no-backup", [Boolean, "skip backup; enhancement will be faster but irreversible"]], - ["-y, --yes", [Boolean, 'skip prompts; assume "yes" and run non-interactively']], - ["-n, --no", [Boolean, 'skip prompts; assume "no" and run non-interactively']], - ["-q, --quiet", [Boolean, 'skip prompts; assume "no" unless -y and hide all output']], + [ + "--overwrite", + [Boolean, "for rapid development; unsafely overwrite sources"], + ], + [ + "--no-backup", + [Boolean, "skip backup; enhancement will be faster but irreversible"], + ], + [ + "-y, --yes", + [Boolean, 'skip prompts; assume "yes" and run non-interactively'], + ], + [ + "-n, --no", + [Boolean, 'skip prompts; assume "no" and run non-interactively'], + ], + [ + "-q, --quiet", + [Boolean, 'skip prompts; assume "no" unless -y and hide all output'], + ], ["-d, --debug", [Boolean, "show detailed error messages"]], ["-j, --json", [Boolean, "display json output (where applicable)"]], ["-h, --help", [Boolean, "display usage information"]], @@ -259,16 +276,20 @@ try { await applyEnhancements(); stopSpinner(); print` {grey * ${messages["version-applied"]}}\n`; - } else print` {grey * ${messages["notion-found"]}: ${messages["version-applied"]}}\n`; + } else { + print` {grey * ${messages["notion-found"]}: ${messages["version-applied"]}}\n`; + } return SUCCESS; } if (insertVersion && insertVersion !== manifest.version) { // diff version already applied print` {grey * ${messages["notion-found"]}: ${messages["version-mismatch"]}}\n`; - const replaceEnhancements = // - ["Y", "y"].includes(await promptConfirmation(messages["prompt-version-replace"])); + // prettier-ignore + const promptReplacement = await promptConfirmation(messages["prompt-version-replace"]); print`\n`; - return replaceEnhancements ? await interactiveRestoreBackup() : CANCELLED; + return ["Y", "y"].includes(promptReplacement) + ? await interactiveRestoreBackup() + : CANCELLED; } else return INCOMPLETE; }, interactiveApplyEnhancements = async () => { @@ -304,7 +325,9 @@ try { return FAILURE; } else if (insertVersion) { print` {grey * ${messages["notion-found"]}: ${messages["version-applied"]}}\n`; - return (await interactiveRestoreBackup()) === INCOMPLETE ? SUCCESS : FAILURE; + return (await interactiveRestoreBackup()) === INCOMPLETE + ? SUCCESS + : FAILURE; } print` {grey * ${messages["notion-found"]}: ${messages["not-applied"]}}\n`; return SUCCESS; @@ -312,7 +335,9 @@ try { promptConfigRemoval = async () => { if (existsSync(configPath)) { print` {grey * ${messages["config-found"]}: ${configPath}}\n`; - if (["Y", "y"].includes(await promptConfirmation(messages["prompt-config-removal"]))) { + // prettier-ignore + const promptRemoval = await promptConfirmation(messages["prompt-config-removal"]); + if (["Y", "y"].includes(promptRemoval)) { print` `; startSpinner(); await removeConfig(); @@ -371,5 +396,7 @@ try { .splice(1) .map((at) => at.replace(/\s{4}/g, " ")) .join("\n")}}`; - } else print`{bold.red Error:} ${message} {grey (run with -d for more information)}\n`; + } else { + print`{bold.red Error:} ${message} {grey (run with -d for more information)}\n`; + } } diff --git a/scripts/enhance-desktop-app.mjs b/scripts/enhance-desktop-app.mjs index 6833abb..44f599d 100755 --- a/scripts/enhance-desktop-app.mjs +++ b/scripts/enhance-desktop-app.mjs @@ -19,7 +19,8 @@ let __notionResources, __enhancerConfig; const nodeRequire = createRequire(import.meta.url), manifest = nodeRequire("../package.json"), platform = - process.platform === "linux" && os.release().toLowerCase().includes("microsoft") + process.platform === "linux" && + os.release().toLowerCase().includes("microsoft") ? "wsl" : process.platform, polyfillWslEnv = (name) => { @@ -55,7 +56,6 @@ const nodeRequire = createRequire(import.meta.url), if (stat.isDirectory()) { files = files.concat(await readdirDeep(file)); } else if (stat.isSymbolicLink()) { - // } else files.push(file); } return files; @@ -70,17 +70,19 @@ const setNotionPath = (path) => { if (__notionResources) return resolve(`${__notionResources}/${path}`); polyfillWslEnv("LOCALAPPDATA"); polyfillWslEnv("PROGRAMW6432"); - const potentialPaths = [ - // [["targeted", "platforms"], "/path/to/notion/resources"] - [["darwin"], `/Users/${process.env.USER}/Applications/Notion.app/Contents/Resources`], - [["darwin"], "/Applications/Notion.app/Contents/Resources"], - [["win32", "wsl"], resolve(`${process.env.LOCALAPPDATA}/Programs/Notion/resources`)], - [["win32", "wsl"], resolve(`${process.env.PROGRAMW6432}/Notion/resources`)], - // https://aur.archlinux.org/packages/notion-app/ - [["linux"], "/opt/notion-app"], - ]; - for (const [targetPlatforms, testPath] of potentialPaths) { - if (!targetPlatforms.includes(platform)) continue; + const potentialPaths = { + win32: [ + resolve(`${process.env.LOCALAPPDATA}/Programs/Notion/resources`), + resolve(`${process.env.PROGRAMW6432}/Notion/resources`), + ], + darwin: [ + `/Users/${process.env.USER}/Applications/Notion.app/Contents/Resources`, + "/Applications/Notion.app/Contents/Resources", + ], + linux: ["/opt/notion-app"], + }; + potentialPaths["wsl"] = potentialPaths["win32"]; + for (const testPath of potentialPaths[platform]) { if (!existsSync(testPath)) continue; __notionResources = testPath; return resolve(`${__notionResources}/${path}`); @@ -88,7 +90,8 @@ const setNotionPath = (path) => { }, // prefer unpacked if both exist getAppPath = () => ["app", "app.asar"].map(getResourcePath).find(existsSync), - getBackupPath = () => ["app.bak", "app.asar.bak"].map(getResourcePath).find(existsSync), + getBackupPath = () => + ["app.bak", "app.asar.bak"].map(getResourcePath).find(existsSync), getConfigPath = () => { if (__enhancerConfig) return __enhancerConfig; const home = platform === "wsl" ? polyfillWslEnv("HOMEPATH") : os.homedir(); @@ -96,6 +99,7 @@ const setNotionPath = (path) => { return __enhancerConfig; }, checkEnhancementVersion = () => { + // prettier-ignore const manifestPath = getResourcePath("app/node_modules/notion-enhancer/package.json"); if (!existsSync(manifestPath)) return undefined; const insertVersion = nodeRequire(manifestPath).version; @@ -127,8 +131,10 @@ const unpackApp = async () => { filter: (_, dest) => !excludedDests.includes(dest), }); // call patch-desktop-app.mjs on each file - const notionScripts = (await readdirDeep(appPath)).filter((file) => file.endsWith(".js")), - scriptUpdates = []; + // prettier-ignore + const notionScripts = (await readdirDeep(appPath)) + .filter((file) => file.endsWith(".js")), + scriptUpdates = []; for (const file of notionScripts) { const scriptId = file.slice(appPath.length + 1, -3).replace(/\\/g, "/"), scriptContent = await fsp.readFile(file, { encoding: "utf8" }), @@ -137,17 +143,18 @@ const unpackApp = async () => { if (changesMade) scriptUpdates.push(fsp.writeFile(file, patchedContent)); } // create package.json + // prettier-ignore const manifestPath = getResourcePath("app/node_modules/notion-enhancer/package.json"), - insertManifest = { ...manifest, main: "electron/init.cjs" }; + jsManifest = { ...manifest, main: "electron/init.js" }; // remove cli-specific fields - delete insertManifest.bin; - delete insertManifest.type; - delete insertManifest.scripts; - delete insertManifest.engines; - delete insertManifest.packageManager; - delete insertManifest.dependencies; - delete insertManifest.devDependencies; - scriptUpdates.push(fsp.writeFile(manifestPath, JSON.stringify(insertManifest))); + delete jsManifest.bin; + delete jsManifest.type; + delete jsManifest.scripts; + delete jsManifest.engines; + delete jsManifest.packageManager; + delete jsManifest.dependencies; + const jsonManifest = JSON.stringify(jsManifest); + scriptUpdates.push(fsp.writeFile(manifestPath, jsonManifest)); await Promise.all(scriptUpdates); return true; }, diff --git a/scripts/patch-desktop-app.mjs b/scripts/patch-desktop-app.mjs index 38d6f01..43fb75b 100755 --- a/scripts/patch-desktop-app.mjs +++ b/scripts/patch-desktop-app.mjs @@ -6,7 +6,8 @@ const patches = { "*": async (scriptId, scriptContent) => { - const prevTriggerFound = /require\(['|"]notion-enhancer['|"]\)/.test(scriptContent); + const prevTriggerPattern = /require\(['|"]notion-enhancer['|"]\)/, + prevTriggerFound = prevTriggerPattern.test(scriptContent); if (prevTriggerFound) return scriptContent; const enhancerTrigger = '\n\n/*notion-enhancer*/require("notion-enhancer")' + @@ -18,6 +19,7 @@ const patches = { // https://github.com/notion-enhancer/desktop/issues/160 // enable the notion:// url scheme/protocol on linux const searchValue = /process.platform === "win32"/g, + // prettier-ignore replaceValue = 'process.platform === "win32" || process.platform === "linux"'; if (scriptContent.includes(replaceValue)) return scriptContent; return scriptContent.replace(searchValue, replaceValue); @@ -36,7 +38,7 @@ const patches = { fileExt = pathname.split(".").reverse()[0], filePath = \`../node_modules/notion-enhancer/\${req.url.slice( schemePrefix.length, - -(search.length + hash.length) + -(search.length + hash.length) || undefined )}\`; callback({ data: require("fs").createReadStream(require("path").resolve(\`\${__dirname}/\${filePath}\`)), diff --git a/scripts/vendor-dependencies.mjs b/scripts/vendor-dependencies.mjs index 34bf199..d3a7fec 100644 --- a/scripts/vendor-dependencies.mjs +++ b/scripts/vendor-dependencies.mjs @@ -9,29 +9,35 @@ import { existsSync } from "node:fs"; import { resolve } from "node:path"; import { fileURLToPath } from "node:url"; -const dependencies = [ - ["twind.min.js", "https://cdn.twind.style"], - ["lucide.min.js", "https://unpkg.com/lucide@0.104.0/dist/umd/lucide.min.js"], - ["jscolor.min.js", "https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.5.1/jscolor.min.js"], -]; +const dependencies = { + "twind.min.js": "https://cdn.twind.style", + "lucide.min.js": "https://unpkg.com/lucide@0.104.0/dist/umd/lucide.min.js", + "jscolor.min.js": + "https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.5.1/jscolor.min.js", +}; -const output = fileURLToPath(new URL("../src/vendor", import.meta.url)); +const output = fileURLToPath(new URL("../src/vendor", import.meta.url)), + write = (file, data) => fsp.writeFile(resolve(`${output}/${file}`), data); if (existsSync(output)) await fsp.rm(output, { recursive: true }); await fsp.mkdir(output); -for (const [file, source] of dependencies) { - const res = await (await fetch(source)).text(); - await fsp.writeFile(resolve(`${output}/${file}`), res); +for (const file in dependencies) { + const source = dependencies[file], + res = await (await fetch(source)).text(); + await write(file, res); } // build content type lookup script from mime-db to avoid // re-processing entire the database every time a file is // requested via notion://www.notion.so/__notion-enhancer/ -const mimeTypes = await (await fetch("https://unpkg.com/mime-db@1.52.0/db.json")).json(), - contentTypes = []; -for (const [type, { extensions, charset }] of Object.entries(mimeTypes)) { +let contentTypes = []; +for (const [type, { extensions, charset }] of Object.entries( + await (await fetch("https://unpkg.com/mime-db@1.52.0/db.json")).json() +)) { if (!extensions) continue; - const contentType = charset ? `${type}; charset=${charset.toLowerCase()}` : type; + const contentType = charset + ? `${type}; charset=${charset.toLowerCase()}` + : type; for (const ext of extensions) contentTypes.push([ext, contentType]); } -const encodedContentTypes = `module.exports=new Map(${JSON.stringify(contentTypes)});`; -await fsp.writeFile(resolve(`${output}/content-types.min.js`), encodedContentTypes); +contentTypes = `module.exports=new Map(${JSON.stringify(contentTypes)});`; +await write("content-types.min.js", contentTypes); diff --git a/src/browser/LICENSE b/src/browser/LICENSE deleted file mode 100644 index b503961..0000000 --- a/src/browser/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 dragonwocky (https://dragonwocky.me/) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/src/browser/README.md b/src/browser/README.md deleted file mode 100644 index 420700e..0000000 --- a/src/browser/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# notion-enhancer/extension - -an enhancer/customiser for the all-in-one productivity workspace notion.so (browser) - -[read the docs online](https://notion-enhancer.github.io/) diff --git a/src/browser/api.js b/src/browser/api.js new file mode 100644 index 0000000..aa073dd --- /dev/null +++ b/src/browser/api.js @@ -0,0 +1,67 @@ +/** + * notion-enhancer + * (c) 2022 dragonwocky (https://dragonwocky.me/) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +"use strict"; + +const platform = "browser", + enhancerVersion = chrome.runtime.getManifest().version, + enhancerUrl = (target) => chrome.runtime.getURL(target); + +const readFile = async (file) => { + file = file.startsWith("http") ? file : enhancerUrl(file); + const res = await fetch(file); + return await res.text(); + }, + readJson = async (file) => { + file = file.startsWith("http") ? file : enhancerUrl(file); + const res = await fetch(file); + return await res.json(); + }, + reloadApp = () => chrome.runtime.sendMessage({ action: "reload" }); + +const initDatabase = (namespace) => { + if (Array.isArray(namespace)) namespace = namespace.join("__"); + namespace = namespace ? namespace + "__" : ""; + return { + get: async (key) => { + key = key.startsWith(namespace) ? key : namespace + key; + return new Promise((res, _rej) => { + chrome.storage.local.get(key, (value) => res(value)); + }); + }, + set: async (key, value) => { + key = key.startsWith(namespace) ? key : namespace + key; + return new Promise((res, _rej) => { + chrome.storage.local.set({ [key]: value }, () => res(value)); + }); + }, + dump: async () => { + const obj = await new Promise((res, _rej) => { + chrome.storage.local.get((value) => res(value)); + }); + if (!namespace) return obj; + let entries = Object.entries(obj); + entries = entries.filter(([key]) => key.startsWith(`${namespace}__`)); + return Object.fromEntries(entries); + }, + populate: async (obj) => { + return new Promise((res, _rej) => { + chrome.storage.local.set(obj, () => res(value)); + }); + }, + }; +}; + +globalThis.__enhancerApi ??= {}; +Object.assign(globalThis.__enhancerApi, { + platform, + enhancerUrl, + enhancerVersion, + readFile, + readJson, + reloadApp, + initDatabase, +}); diff --git a/src/browser/env/env.mjs b/src/browser/env/env.mjs deleted file mode 100644 index 17c905d..0000000 --- a/src/browser/env/env.mjs +++ /dev/null @@ -1,41 +0,0 @@ -/* - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** environment-specific methods and constants */ - -/** - * the environment/platform name code is currently being executed in - * @constant - * @type {string} - */ -export const name = 'extension'; - -/** - * the current version of the enhancer - * @constant - * @type {string} - */ -export const version = chrome.runtime.getManifest().version; - -/** - * open the enhancer's menu - * @type {function} - */ -export const focusMenu = () => chrome.runtime.sendMessage({ action: 'focusMenu' }); - -/** - * focus an active notion tab - * @type {function} - */ -export const focusNotion = () => chrome.runtime.sendMessage({ action: 'focusNotion' }); - -/** - * reload all notion and enhancer menu tabs to apply changes - * @type {function} - */ -export const reload = () => chrome.runtime.sendMessage({ action: 'reload' }); diff --git a/src/browser/env/fs.mjs b/src/browser/env/fs.mjs deleted file mode 100644 index 020a37d..0000000 --- a/src/browser/env/fs.mjs +++ /dev/null @@ -1,48 +0,0 @@ -/* - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** environment-specific file reading */ - -/** - * transform a path relative to the enhancer root directory into an absolute path - * @param {string} path - a url or within-the-enhancer filepath - * @returns {string} an absolute filepath - */ -export const localPath = chrome.runtime.getURL; - -/** - * fetch and parse a json file's contents - * @param {string} path - a url or within-the-enhancer filepath - * @param {object=} opts - the second argument of a fetch() request - * @returns {object} the json value of the requested file as a js object - */ -export const getJSON = (path, opts = {}) => - fetch(path.startsWith('http') ? path : localPath(path), opts).then((res) => res.json()); - -/** - * fetch a text file's contents - * @param {string} path - a url or within-the-enhancer filepath - * @param {object=} opts - the second argument of a fetch() request - * @returns {string} the text content of the requested file - */ -export const getText = (path, opts = {}) => - fetch(path.startsWith('http') ? path : localPath(path), opts).then((res) => res.text()); - -/** - * check if a file exists - * @param {string} path - a url or within-the-enhancer filepath - * @returns {boolean} whether or not the file exists - */ -export const isFile = async (path) => { - try { - await fetch(path.startsWith('http') ? path : localPath(path)); - return true; - } catch { - return false; - } -}; diff --git a/src/browser/env/storage.mjs b/src/browser/env/storage.mjs deleted file mode 100644 index 0018513..0000000 --- a/src/browser/env/storage.mjs +++ /dev/null @@ -1,116 +0,0 @@ -/* - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** environment-specific data persistence */ - -const _queue = [], - _onChangeListeners = []; - -/** - * get persisted data - * @param {string[]} path - the path of keys to the value being fetched - * @param {unknown=} fallback - a default value if the path is not matched - * @returns {Promise} value ?? fallback - */ -export const get = (path, fallback = undefined) => { - if (!path.length) return fallback; - return new Promise((res, rej) => - chrome.storage.local.get(async (values) => { - let value = values; - while (path.length) { - if (value === undefined) { - value = fallback; - break; - } - value = value[path.shift()]; - } - res(value ?? fallback); - }) - ); -}; - -/** - * persist data - * @param {string[]} path - the path of keys to the value being set - * @param {unknown} value - the data to save - * @returns {Promise} resolves when data has been saved - */ -export const set = (path, value) => { - if (!path.length) return undefined; - const precursor = _queue[_queue.length - 1] || undefined, - interaction = new Promise(async (res, rej) => { - if (precursor !== undefined) { - await precursor; - _queue.shift(); - } - const pathClone = [...path], - namespace = path[0]; - chrome.storage.local.get(async (values) => { - let pointer = values, - old; - while (path.length) { - const key = path.shift(); - if (!path.length) { - old = pointer[key]; - pointer[key] = value; - break; - } - pointer[key] = pointer[key] ?? {}; - pointer = pointer[key]; - } - chrome.storage.local.set({ [namespace]: values[namespace] }, () => { - _onChangeListeners.forEach((listener) => - listener({ path: pathClone, new: value, old }) - ); - res(value); - }); - }); - }); - _queue.push(interaction); - return interaction; -}; - -/** - * create a wrapper for accessing a partition of the storage - * @param {string[]} namespace - the path of keys to prefix all storage requests with - * @param {function=} get - the storage get function to be wrapped - * @param {function=} set - the storage set function to be wrapped - * @returns {object} an object with the wrapped get/set functions - */ -export const db = (namespace, getFunc = get, setFunc = set) => { - if (typeof namespace === 'string') namespace = [namespace]; - return { - get: (path = [], fallback = undefined) => getFunc([...namespace, ...path], fallback), - set: (path, value) => setFunc([...namespace, ...path], value), - }; -}; - -/** - * add an event listener for changes in storage - * @param {onStorageChangeCallback} callback - called whenever a change in - * storage is initiated from the current process - */ -export const addChangeListener = (callback) => { - _onChangeListeners.push(callback); -}; - -/** - * remove a listener added with storage.addChangeListener - * @param {onStorageChangeCallback} callback - */ -export const removeChangeListener = (callback) => { - _onChangeListeners = _onChangeListeners.filter((listener) => listener !== callback); -}; - -/** - * @callback onStorageChangeCallback - * @param {object} event - * @param {string} event.path- the path of keys to the changed value - * @param {string=} event.new - the new value being persisted to the store - * @param {string=} event.old - the previous value associated with the key - */ diff --git a/src/browser/init.js b/src/browser/init.js index e8de939..344af76 100644 --- a/src/browser/init.js +++ b/src/browser/init.js @@ -4,32 +4,34 @@ * (https://notion-enhancer.github.io/) under the MIT license */ -'use strict'; +"use strict"; (async () => { - const site = location.host.endsWith('.notion.site'), - page = location.pathname.split(/[/-]/g).reverse()[0].length === 32, - whitelisted = ['/', '/onboarding'].includes(location.pathname), - signedIn = localStorage['LRU:KeyValueStore2:current-user-id']; + const enhancerApi = await import("./api.js"); + globalThis.__enhancerApi = enhancerApi; + // const site = location.host.endsWith('.notion.site'), + // page = location.pathname.split(/[/-]/g).reverse()[0].length === 32, + // whitelisted = ['/', '/onboarding'].includes(location.pathname), + // signedIn = localStorage['LRU:KeyValueStore2:current-user-id']; - if (site || page || (whitelisted && signedIn)) { - const api = await import(chrome.runtime.getURL('api/index.mjs')), - { fs, registry, web } = api; + // if (site || page || (whitelisted && signedIn)) { + // const api = await import(chrome.runtime.getURL('api/index.mjs')), + // { fs, registry, web } = api; - for (const mod of await registry.list((mod) => registry.enabled(mod.id))) { - for (const sheet of mod.css?.client || []) { - web.loadStylesheet(`repo/${mod._dir}/${sheet}`); - } - for (let script of mod.js?.client || []) { - script = await import(fs.localPath(`repo/${mod._dir}/${script}`)); - script.default(api, await registry.db(mod.id)); - } - } + // for (const mod of await registry.list((mod) => registry.enabled(mod.id))) { + // for (const sheet of mod.css?.client || []) { + // web.loadStylesheet(`repo/${mod._dir}/${sheet}`); + // } + // for (let script of mod.js?.client || []) { + // script = await import(fs.localPath(`repo/${mod._dir}/${script}`)); + // script.default(api, await registry.db(mod.id)); + // } + // } - const errors = await registry.errors(); - if (errors.length) { - console.log('[notion-enhancer] registry errors:'); - console.table(errors); - } - } + // const errors = await registry.errors(); + // if (errors.length) { + // console.log('[notion-enhancer] registry errors:'); + // console.table(errors); + // } + // } })(); diff --git a/src/common/.github/workflows/update-parents.yml b/src/common/.github/workflows/update-parents.yml deleted file mode 100644 index ac428e4..0000000 --- a/src/common/.github/workflows/update-parents.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: 'update parent repositories' - -on: - push: - branches: - - dev - -jobs: - sync: - name: update parent - runs-on: ubuntu-latest - strategy: - matrix: - repo: ['notion-enhancer/extension', 'notion-enhancer/desktop'] - steps: - - name: checkout repo - uses: actions/checkout@v2 - with: - token: ${{ secrets.CI_TOKEN }} - submodules: true - repository: ${{ matrix.repo }} - - name: pull updates - run: | - git pull --recurse-submodules - git submodule update --remote --recursive - - name: commit changes - uses: stefanzweifel/git-auto-commit-action@v4 - with: - commit_message: '[${{ github.event.repository.name }}] ${{ github.event.head_commit.message }}' diff --git a/src/common/LICENSE b/src/common/LICENSE deleted file mode 100644 index b503961..0000000 --- a/src/common/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 dragonwocky (https://dragonwocky.me/) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/src/common/README.md b/src/common/README.md deleted file mode 100644 index ab8ffc8..0000000 --- a/src/common/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# notion-enhancer/api - -the standard api available within the notion-enhancer - -[read the docs online](https://notion-enhancer.github.io/documentation/api) diff --git a/src/common/electron.mjs b/src/common/electron.mjs deleted file mode 100644 index 1492333..0000000 --- a/src/common/electron.mjs +++ /dev/null @@ -1,106 +0,0 @@ -/** - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** - * access to electron renderer apis - * @namespace electron - */ -import * as _api from './index.mjs'; // trick jsdoc - -/** - * access to the electron BrowserWindow instance for the current window - * see https://www.electronjs.org/docs/latest/api/browser-window - * @type {BrowserWindow} - * @process electron (renderer process) - */ -export const browser = globalThis.__enhancerElectronApi?.browser; - -/** - * access to the electron webFrame instance for the current page - * see https://www.electronjs.org/docs/latest/api/web-frame - * @type {webFrame} - * @process electron (renderer process) - */ -export const webFrame = globalThis.__enhancerElectronApi?.webFrame; - -/** - * send a message to the main electron process - * @param {string} channel - the message identifier - * @param {any} data - the data to pass along with the message - * @param {string=} namespace - a prefix for the message to categorise - * it as e.g. enhancer-related. this should not be changed unless replicating - * builtin ipc events. - * @process electron (renderer process) - */ -export const sendMessage = (channel, data, namespace = 'notion-enhancer') => { - if (globalThis.__enhancerElectronApi) { - globalThis.__enhancerElectronApi.ipcRenderer.sendMessage(channel, data, namespace); - } -}; - -/** - * send a message to the webview's parent renderer process - * @param {string} channel - the message identifier - * @param {any} data - the data to pass along with the message - * @param {string=} namespace - a prefix for the message to categorise - * it as e.g. enhancer-related. this should not be changed unless replicating - * builtin ipc events. - * @process electron (renderer process) - */ -export const sendMessageToHost = (channel, data, namespace = 'notion-enhancer') => { - if (globalThis.__enhancerElectronApi) { - globalThis.__enhancerElectronApi.ipcRenderer.sendMessageToHost(channel, data, namespace); - } -}; - -/** - * receive a message from either the main process or - * the webview's parent renderer process - * @param {string} channel - the message identifier to listen for - * @param {function} callback - the message handler, passed the args (event, data) - * @param {string=} namespace - a prefix for the message to categorise - * it as e.g. enhancer-related. this should not be changed unless replicating - * builtin ipc events. - * @process electron (renderer process) - */ -export const onMessage = (channel, callback, namespace = 'notion-enhancer') => { - if (globalThis.__enhancerElectronApi) { - globalThis.__enhancerElectronApi.ipcRenderer.onMessage(channel, callback, namespace); - } -}; - -/** - * require() notion app files - * @param {string} path - within notion/resources/app/ e.g. main/createWindow.js - * @process electron (main process) - */ -export const notionRequire = (path) => { - return globalThis.__enhancerElectronApi - ? globalThis.__enhancerElectronApi.notionRequire(path) - : null; -}; - -/** - * get all available app windows excluding the menu - * @process electron (main process) - */ -export const getNotionWindows = () => { - return globalThis.__enhancerElectronApi - ? globalThis.__enhancerElectronApi.getNotionWindows() - : null; -}; - -/** - * get the currently focused notion window - * @process electron (main process) - */ -export const getFocusedNotionWindow = () => { - return globalThis.__enhancerElectronApi - ? globalThis.__enhancerElectronApi.getFocusedNotionWindow() - : null; -}; diff --git a/src/common/env.mjs b/src/common/env.mjs deleted file mode 100644 index 27f3ac4..0000000 --- a/src/common/env.mjs +++ /dev/null @@ -1,46 +0,0 @@ -/** - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** - * environment-specific methods and constants - * @namespace env - */ - -import * as env from '../env/env.mjs'; - -/** - * the environment/platform name code is currently being executed in - * @constant - * @type {string} - */ -export const name = env.name; - -/** - * the current version of the enhancer - * @constant - * @type {string} - */ -export const version = env.version; - -/** - * open the enhancer's menu - * @type {function} - */ -export const focusMenu = env.focusMenu; - -/** - * focus an active notion tab - * @type {function} - */ -export const focusNotion = env.focusNotion; - -/** - * reload all notion and enhancer menu tabs to apply changes - * @type {function} - */ -export const reload = env.reload; diff --git a/src/common/fmt.mjs b/src/common/fmt.mjs deleted file mode 100644 index 57660cb..0000000 --- a/src/common/fmt.mjs +++ /dev/null @@ -1,137 +0,0 @@ -/** - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** - * helpers for formatting or parsing text - * @namespace fmt - */ - -import { fs } from './index.mjs'; - -/** - * transform a heading into a slug (a lowercase alphanumeric string separated by hyphens), - * e.g. for use as an anchor id - * @param {string} heading - the original heading to be slugified - * @param {Set=} slugs - a list of pre-generated slugs to avoid duplicates - * @returns {string} the generated slug - */ -export const slugger = (heading, slugs = new Set()) => { - heading = heading - .replace(/\s/g, '-') - .replace(/[^A-Za-z0-9-_]/g, '') - .toLowerCase(); - let i = 0, - slug = heading; - while (slugs.has(slug)) { - i++; - slug = `${heading}-${i}`; - } - return slug; -}; - -/** - * generate a reasonably random uuidv4 string. uses crypto implementation if available - * (from https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid) - * @returns {string} a uuidv4 - */ -export const uuidv4 = () => { - if (crypto?.randomUUID) return crypto.randomUUID(); - return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => - (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16) - ); -}; - -/** - * log-based shading of an rgb color, from - * https://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors - * @param {number} shade - a decimal amount to shade the color. - * 1 = white, 0 = the original color, -1 = black - * @param {string} color - the rgb color - * @returns {string} the shaded color - */ -export const rgbLogShade = (shade, color) => { - const int = parseInt, - round = Math.round, - [a, b, c, d] = color.split(','), - t = shade < 0 ? 0 : shade * 255 ** 2, - p = shade < 0 ? 1 + shade : 1 - shade; - return ( - 'rgb' + - (d ? 'a(' : '(') + - round((p * int(a[3] == 'a' ? a.slice(5) : a.slice(4)) ** 2 + t) ** 0.5) + - ',' + - round((p * int(b) ** 2 + t) ** 0.5) + - ',' + - round((p * int(c) ** 2 + t) ** 0.5) + - (d ? ',' + d : ')') - ); -}; - -/** - * pick a contrasting color e.g. for text on a variable color background - * using the hsp (perceived brightness) constants from http://alienryderflex.com/hsp.html - * @param {number} r - red (0-255) - * @param {number} g - green (0-255) - * @param {number} b - blue (0-255) - * @returns {string} the contrasting rgb color, white or black - */ -export const rgbContrast = (r, g, b) => { - return Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b)) > 165.75 - ? 'rgb(0,0,0)' - : 'rgb(255,255,255)'; -}; - -const patterns = { - alphanumeric: /^[\w\.-]+$/, - uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, - semver: - /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/i, - email: - /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i, - url: /^[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,64}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/i, - color: /^(?:#|0x)(?:[a-f0-9]{3}|[a-f0-9]{6})\b|(?:rgb|hsl)a?\([^\)]*\)$/i, -}; -function test(str, pattern) { - const match = str.match(pattern); - return !!(match && match.length); -} - -/** - * test the type of a value. unifies builtin, regex, and environment/api checks - * @param {unknown} value - the value to check - * @param {string|string[]} type - the type the value should be or a list of allowed values - * @returns {boolean} whether or not the value matches the type - */ -export const is = async (value, type, { extension = '' } = {}) => { - extension = !value || !value.endsWith || value.endsWith(extension); - if (Array.isArray(type)) { - return type.includes(value); - } - switch (type) { - case 'array': - return Array.isArray(value); - case 'object': - return value && typeof value === 'object' && !Array.isArray(value); - case 'undefined': - case 'boolean': - case 'number': - return typeof value === type && extension; - case 'string': - return typeof value === type && extension; - case 'alphanumeric': - case 'uuid': - case 'semver': - case 'email': - case 'url': - case 'color': - return typeof value === 'string' && test(value, patterns[type]) && extension; - case 'file': - return typeof value === 'string' && value && (await fs.isFile(value)) && extension; - } - return false; -}; diff --git a/src/common/fs.mjs b/src/common/fs.mjs deleted file mode 100644 index fa18d7b..0000000 --- a/src/common/fs.mjs +++ /dev/null @@ -1,55 +0,0 @@ -/** - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** - * environment-specific file reading - * @namespace fs - */ - -import * as fs from '../env/fs.mjs'; - -/** - * get an absolute path to files within notion - * @param {string} path - relative to the root notion/resources/app/ e.g. renderer/search.js - * @process electron - */ -export const notionPath = fs.notionPath; - -/** - * transform a path relative to the enhancer root directory into an absolute path - * @type {function} - * @param {string} path - a url or within-the-enhancer filepath - * @returns {string} an absolute filepath - */ -export const localPath = fs.localPath; - -/** - * fetch and parse a json file's contents - * @type {function} - * @param {string} path - a url or within-the-enhancer filepath - * @param {FetchOptions=} opts - the second argument of a fetch() request - * @returns {unknown} the json value of the requested file as a js object - */ -export const getJSON = fs.getJSON; - -/** - * fetch a text file's contents - * @type {function} - * @param {string} path - a url or within-the-enhancer filepath - * @param {FetchOptions=} opts - the second argument of a fetch() request - * @returns {string} the text content of the requested file - */ -export const getText = fs.getText; - -/** - * check if a file exists - * @type {function} - * @param {string} path - a url or within-the-enhancer filepath - * @returns {boolean} whether or not the file exists - */ -export const isFile = fs.isFile; diff --git a/src/common/index.cjs b/src/common/index.cjs deleted file mode 100644 index c130ac1..0000000 --- a/src/common/index.cjs +++ /dev/null @@ -1,21 +0,0 @@ -var le=Object.defineProperty;var Xe=e=>le(e,"__esModule",{value:!0});var y=(e,t)=>{Xe(e);for(var n in t)le(e,n,{get:t[n],enumerable:!0})};y(exports,{components:()=>R,electron:()=>V,env:()=>j,fmt:()=>h,fs:()=>u,notion:()=>X,registry:()=>g,storage:()=>_,web:()=>o});var j={};y(j,{focusMenu:()=>Ye,focusNotion:()=>De,name:()=>Ge,reload:()=>et,version:()=>Qe});"use strict";var de=globalThis.__enhancerElectronApi.platform,pe=globalThis.__enhancerElectronApi.version,ue=globalThis.__enhancerElectronApi.focusMenu,he=globalThis.__enhancerElectronApi.focusNotion,fe=globalThis.__enhancerElectronApi.reload;"use strict";var Ge=de,Qe=pe,Ye=ue,De=he,et=fe;var u={};y(u,{getJSON:()=>rt,getText:()=>st,isFile:()=>ot,localPath:()=>nt,notionPath:()=>tt});"use strict";var M=globalThis.__enhancerElectronApi.notionPath,L=e=>`notion://www.notion.so/__notion-enhancer/${e}`,me=(e,t={})=>{if(e=e.replace(/^https:\/\/www\.notion\.so\//,"notion://www.notion.so/"),e.startsWith("http")||e.startsWith("notion://"))return fetch(e,t).then(r=>r.json());try{return globalThis.__enhancerElectronApi.nodeRequire(`notion-enhancer/${e}`)}catch{return fetch(L(e),t).then(s=>s.json())}},ge=(e,t={})=>{if(e=e.replace(/^https:\/\/www\.notion\.so\//,"notion://www.notion.so/"),e.startsWith("http")||e.startsWith("notion://"))return fetch(e,t).then(r=>r.text());try{return globalThis.__enhancerElectronApi.nodeRequire("fs").readFileSync(M(`notion-enhancer/${e}`))}catch{return fetch(L(e),t).then(s=>s.text())}},ye=async e=>{try{let t=globalThis.__enhancerElectronApi.nodeRequire("fs");if(e.startsWith("http"))await fetch(e);else try{t.existsSync(M(`notion-enhancer/${e}`))}catch{await fetch(L(e))}return!0}catch{return!1}};"use strict";var tt=M,nt=L,rt=me,st=ge,ot=ye;var _={};y(_,{addChangeListener:()=>lt,db:()=>ct,get:()=>it,removeChangeListener:()=>dt,set:()=>at});"use strict";var H=(e,t=void 0)=>globalThis.__enhancerElectronApi.db.get(e,t),I=(e,t)=>globalThis.__enhancerElectronApi.db.set(e,t),we=(e,t=H,n=I)=>(typeof e=="string"&&(e=[e]),{get:(r=[],s=void 0)=>t([...e,...r],s),set:(r,s)=>n([...e,...r],s)}),ve=e=>globalThis.__enhancerElectronApi.db.addChangeListener(e),be=e=>globalThis.__enhancerElectronApi.db.removeChangeListener(e);"use strict";var it=H,at=I,ct=we,lt=ve,dt=be;var V={};y(V,{browser:()=>pt,getFocusedNotionWindow:()=>wt,getNotionWindows:()=>yt,notionRequire:()=>gt,onMessage:()=>mt,sendMessage:()=>ht,sendMessageToHost:()=>ft,webFrame:()=>ut});"use strict";var pt=globalThis.__enhancerElectronApi?.browser,ut=globalThis.__enhancerElectronApi?.webFrame,ht=(e,t,n="notion-enhancer")=>{globalThis.__enhancerElectronApi&&globalThis.__enhancerElectronApi.ipcRenderer.sendMessage(e,t,n)},ft=(e,t,n="notion-enhancer")=>{globalThis.__enhancerElectronApi&&globalThis.__enhancerElectronApi.ipcRenderer.sendMessageToHost(e,t,n)},mt=(e,t,n="notion-enhancer")=>{globalThis.__enhancerElectronApi&&globalThis.__enhancerElectronApi.ipcRenderer.onMessage(e,t,n)},gt=e=>globalThis.__enhancerElectronApi?globalThis.__enhancerElectronApi.notionRequire(e):null,yt=()=>globalThis.__enhancerElectronApi?globalThis.__enhancerElectronApi.getNotionWindows():null,wt=()=>globalThis.__enhancerElectronApi?globalThis.__enhancerElectronApi.getFocusedNotionWindow():null;var X={};y(X,{create:()=>xt,get:()=>xe,getPageID:()=>J,getSpaceID:()=>T,getUserID:()=>_e,search:()=>vt,set:()=>bt,sign:()=>$t,upload:()=>_t});"use strict";var m=e=>(e?.length===32&&!e.includes("-")&&(e=e.replace(/([\d\w]{8})([\d\w]{4})([\d\w]{4})([\d\w]{4})([\d\w]{12})/,"$1-$2-$3-$4-$5")),e),xe=async(e,t="block")=>{e=m(e);let n=await u.getJSON("https://www.notion.so/api/v3/getRecordValues",{headers:{"Content-Type":"application/json"},body:JSON.stringify({requests:[{table:t,id:e}]}),method:"POST"});return n?.results?.[0]?.value||n},_e=()=>JSON.parse(localStorage["LRU:KeyValueStore2:current-user-id"]||{}).value,J=()=>m(o.queryParams().get("p")||location.pathname.split(/(-|\/)/g).reverse()[0]),K,T=async()=>(K||(K=(await xe(J())).space_id),K),vt=async(e="",t=20,n=T())=>(n=m(await n),await u.getJSON("https://www.notion.so/api/v3/search",{headers:{"Content-Type":"application/json"},body:JSON.stringify({type:"BlocksInSpace",query:e,spaceId:n,limit:t,filters:{isDeletedOnly:!1,excludeTemplates:!1,isNavigableOnly:!1,requireEditPermissions:!1,ancestors:[],createdBy:[],editedBy:[],lastEditedTime:{},createdTime:{}},sort:"Relevance",source:"quick_find"}),method:"POST"})),bt=async({recordID:e,recordTable:t="block",spaceID:n=T(),path:r=[]},s={})=>{n=m(await n),e=m(e);let c=await u.getJSON("https://www.notion.so/api/v3/saveTransactions",{headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:h.uuidv4(),transactions:[{id:h.uuidv4(),spaceId:n,operations:[{pointer:{table:t,id:e,spaceId:n},path:r,command:r.length?"set":"update",args:s}]}]}),method:"POST"});return c.errorId?c:!0},xt=async({recordValue:e={},recordTable:t="block"}={},{prepend:n=!1,siblingID:r=void 0,parentID:s=J(),parentTable:c="block",spaceID:a=T(),userID:i=_e()}={})=>{a=m(await a),s=m(s),r=m(r);let d=m(e?.id??h.uuidv4()),x=[],A={type:"text",id:d,version:0,created_time:new Date().getTime(),last_edited_time:new Date().getTime(),parent_id:s,parent_table:c,alive:!0,created_by_table:"notion_user",created_by_id:i,last_edited_by_table:"notion_user",last_edited_by_id:i,space_id:a,permissions:[{type:"user_permission",role:"editor",user_id:i}]};c==="space"?(s=a,A.parent_id=a,x.push("pages"),A.type="page"):c==="collection_view"?(x.push("page_sort"),A.type="page"):x.push("content");let ce=await u.getJSON("https://www.notion.so/api/v3/saveTransactions",{headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:h.uuidv4(),transactions:[{id:h.uuidv4(),spaceId:a,operations:[{pointer:{table:c,id:s,spaceId:a},path:x,command:n?"listBefore":"listAfter",args:{...r?{after:r}:{},id:d}},{pointer:{table:t,id:d,spaceId:a},path:[],command:"set",args:{...A,...e}}]}]}),method:"POST"});return ce.errorId?ce:d},_t=async(e,{pageID:t=J(),spaceID:n=T()}={})=>{n=m(await n),t=m(t);let r=await u.getJSON("https://www.notion.so/api/v3/getUploadFileUrl",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({bucket:"secure",name:e.name,contentType:e.type,record:{table:"block",id:t,spaceId:n}})});return r.errorId?r:(fetch(r.signedPutUrl,{method:"PUT",headers:{"content-type":e.type},body:e}),r.url)},$t=(e,t,n="block")=>(e.startsWith("/")&&(e=`https://notion.so${e}`),e.includes("secure.notion-static.com")&&(e=new URL(e),e=`https://www.notion.so/signed/${encodeURIComponent(e.origin+e.pathname)}?table=${n}&id=${t}`),e);var h={};y(h,{is:()=>kt,rgbContrast:()=>Lt,rgbLogShade:()=>jt,slugger:()=>At,uuidv4:()=>Et});"use strict";var At=(e,t=new Set)=>{e=e.replace(/\s/g,"-").replace(/[^A-Za-z0-9-_]/g,"").toLowerCase();let n=0,r=e;for(;t.has(r);)n++,r=`${e}-${n}`;return r},Et=()=>crypto?.randomUUID?crypto.randomUUID():([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,e=>(e^crypto.getRandomValues(new Uint8Array(1))[0]&15>>e/4).toString(16)),jt=(e,t)=>{var n=parseInt,r=Math.round,[s,c,t,a]=t.split(","),i=e<0,d=i?0:e*255**2,i=i?1+e:1-e;return"rgb"+(a?"a(":"(")+r((i*n(s[3]=="a"?s.slice(5):s.slice(4))**2+d)**.5)+","+r((i*n(c)**2+d)**.5)+","+r((i*n(t)**2+d)**.5)+(a?","+a:")")},Lt=(e,t,n)=>Math.sqrt(.299*(e*e)+.587*(t*t)+.114*(n*n))>165.75?"rgb(0,0,0)":"rgb(255,255,255)",Tt={alphanumeric:/^[\w\.-]+$/,uuid:/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,semver:/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/i,email:/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i,url:/^[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,64}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/i,color:/^(?:#|0x)(?:[a-f0-9]{3}|[a-f0-9]{6})\b|(?:rgb|hsl)a?\([^\)]*\)$/i};function St(e,t){let n=e.match(t);return!!(n&&n.length)}var kt=async(e,t,{extension:n=""}={})=>{if(n=!e||!e.endsWith||e.endsWith(n),Array.isArray(t))return t.includes(e);switch(t){case"array":return Array.isArray(e);case"object":return e&&typeof e=="object"&&!Array.isArray(e);case"undefined":case"boolean":case"number":return typeof e===t&&n;case"string":return typeof e===t&&n;case"alphanumeric":case"uuid":case"semver":case"email":case"url":case"color":return typeof e=="string"&&St(e,Tt[t])&&n;case"file":return typeof e=="string"&&e&&await u.isFile(e)&&n}return!1};var g={};y(g,{core:()=>Ae,db:()=>Ut,enabled:()=>zt,errors:()=>Wt,get:()=>ee,list:()=>D,optionDefault:()=>je,optionTypes:()=>Jt,profileDB:()=>G,profileName:()=>Ee,supportedEnvs:()=>Mt});"use strict";var l=async(e,t,n,r,{extension:s="",error:c=`invalid ${t} (${s?`${s} `:""}${r}): ${JSON.stringify(n)}`,optional:a=!1}={})=>{let i;for(let d of Array.isArray(r)?[r]:r.split("|"))if(d==="file"?i=n&&!n.startsWith("http")?await h.is(`repo/${e._dir}/${n}`,d,{extension:s}):!1:i=await h.is(n,d,{extension:s}),i)break;return i||a&&await h.is(n,"undefined")?!0:(c&&e._err(c),!1)},Pt=async e=>(e.environments=e.environments??g.supportedEnvs,await l(e,"environments",e.environments,"array")?e.environments.map(n=>l(e,"environments.env",n,g.supportedEnvs)):!1),Ct=async e=>{if(!await l(e,"tags",e.tags,"array"))return!1;let n=["core","extension","theme","integration"];if(!e.tags.filter(i=>n.includes(i)).length)return e._err(`invalid tags (must contain at least one of 'core', 'extension', 'theme' or 'integration'): - ${JSON.stringify(e.tags)}`),!1;let s=e.tags.includes("theme"),c=e.tags.includes("light")||e.tags.includes("dark"),a=e.tags.includes("light")&&e.tags.includes("dark");return s&&(!c||a)?(e._err(`invalid tags (themes must be either 'light' or 'dark', not neither or both): - ${JSON.stringify(e.tags)}`),!1):e.tags.map(i=>l(e,"tags.tag",i,"string"))},Ot=async e=>await l(e,"authors",e.authors,"array")?e.authors.map(n=>[l(e,"authors.author.name",n.name,"string"),l(e,"authors.author.email",n.email,"email",{optional:!0}),l(e,"authors.author.homepage",n.homepage,"url"),l(e,"authors.author.avatar",n.avatar,"url")]):!1,Nt=async e=>{if(!await l(e,"css",e.css,"object"))return!1;let n=[];for(let r of["frame","client","menu"]){if(!e.css[r])continue;let s=await l(e,`css.${r}`,e.css[r],"array");s&&(s=e.css[r].map(c=>l(e,`css.${r}.file`,c,"file",{extension:".css"}))),n.push(s)}return n},Rt=async e=>{if(!await l(e,"js",e.js,"object"))return!1;let n=[];for(let r of["frame","client","menu"]){if(!e.js[r])continue;let s=await l(e,`js.${r}`,e.js[r],"array");s&&(s=e.js[r].map(c=>l(e,`js.${r}.file`,c,"file",{extension:".mjs"}))),n.push(s)}if(e.js.electron)if(await l(e,"js.electron",e.js.electron,"array"))for(let s of e.js.electron){if(!await l(e,"js.electron.file",s,"object")){n.push(!1);continue}n.push([l(e,"js.electron.file.source",s.source,"file",{extension:".cjs"}),l(e,"js.electron.file.target",s.target,"string",{extension:".js"})])}else n.push(!1);return n},qt=async e=>{if(!await l(e,"options",e.options,"array"))return!1;let n=[];for(let r of e.options){let s="options.option";if(!await l(e,`${s}.type`,r.type,g.optionTypes)){n.push(!1);continue}switch(r.environments=r.environments??g.supportedEnvs,n.push([l(e,`${s}.key`,r.key,"alphanumeric"),l(e,`${s}.label`,r.label,"string"),l(e,`${s}.tooltip`,r.tooltip,"string",{optional:!0}),l(e,`${s}.environments`,r.environments,"array").then(a=>a?r.environments.map(i=>l(e,`${s}.environments.env`,i,g.supportedEnvs)):!1)]),r.type){case"toggle":n.push(l(e,`${s}.value`,r.value,"boolean"));break;case"select":{let a=await l(e,`${s}.values`,r.values,"array");a&&(a=r.values.map(i=>l(e,`${s}.values.value`,i,"string"))),n.push(a);break}case"text":case"hotkey":n.push(l(e,`${s}.value`,r.value,"string"));break;case"number":case"color":n.push(l(e,`${s}.value`,r.value,r.type));break;case"file":{let a=await l(e,`${s}.extensions`,r.extensions,"array");a&&(a=r.extensions.map(i=>l(e,`${s}.extensions.extension`,i,"string"))),n.push(a);break}}}return n};async function $e(e){let t=[l(e,"name",e.name,"string"),l(e,"id",e.id,"uuid"),l(e,"version",e.version,"semver"),Pt(e),l(e,"description",e.description,"string"),l(e,"preview",e.preview,"file|url",{optional:!0}),Ct(e),Ot(e),Nt(e),Rt(e),qt(e)];do t=await Promise.all(t.flat(1/0));while(t.some(n=>Array.isArray(n)));return t.every(n=>n)}"use strict";var Ae=["a6621988-551d-495a-97d8-3c568bca2e9e","0f0bf8b6-eae6-4273-b307-8fc43f2ee082","36a2ffc9-27ff-480e-84a7-c7700a7d232d"],Mt=["linux","win32","darwin","extension"],Jt=["toggle","select","text","number","color","file","hotkey"],Ee=async()=>_.get(["currentprofile"],"default"),G=async()=>_.db(["profiles",await Ee()]),Q,Y=[],D=async(e=t=>!0)=>{Q||(Q=new Promise(async(n,r)=>{let s=[];for(let c of await u.getJSON("repo/registry.json"))try{let a={...await u.getJSON(`repo/${c}/mod.json`),_dir:c,_err:i=>Y.push({source:c,message:i})};await $e(a)&&s.push(a)}catch{Y.push({source:c,message:"invalid mod.json"})}n(s)}));let t=[];for(let n of await Q)await e(n)&&t.push(n);return t},Wt=async()=>(await D(),Y),ee=async e=>(await D(t=>t.id===e))[0],zt=async e=>(await ee(e)).environments.includes(j.name)?Ae.includes(e)?!0:(await G()).get(["_mods",e],!1):!1,je=async(e,t)=>{let n=await ee(e),r=n.options.find(s=>s.key===t);if(!!r)switch(r.type){case"toggle":case"text":case"number":case"color":case"hotkey":return r.value;case"select":return r.values[0];case"file":return}},Ut=async e=>{let t=await G();return _.db([e],async(n,r=void 0)=>(typeof n=="string"&&(n=[n]),n.length===2&&(r=await je(e,n[1])??r),t.get(n,r)),t.set)};var o={};y(o,{addDocumentObserver:()=>Gt,addHotkeyListener:()=>Kt,copyToClipboard:()=>It,empty:()=>Ft,escape:()=>Te,html:()=>ke,loadStylesheet:()=>Ht,queryParams:()=>Bt,raw:()=>Se,readFromClipboard:()=>Vt,removeDocumentObserver:()=>Qt,removeHotkeyListener:()=>Xt,render:()=>Pe,whenReady:()=>Zt});"use strict";var Le=!1,S=[],te,W=[],ne=[],Zt=(e=[])=>new Promise((t,n)=>{let r=()=>{let s=setInterval(c,100);function c(){!e.every(i=>document.querySelector(i))||(clearInterval(s),t(!0))}c()};document.readyState!=="complete"?document.addEventListener("readystatechange",s=>{document.readyState==="complete"&&r()}):r()}),Bt=()=>new URLSearchParams(window.location.search),Te=e=>e.replace(/&/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""").replace(/\\/g,"\"),Se=(e,...t)=>{let n=e.map(r=>r+(["string","number"].includes(typeof t[0])?t.shift():Te(JSON.stringify(t.shift(),null,2)??""))).join("");return n.includes("r.trim()).filter(r=>r.length).join(" ")},ke=(e,...t)=>{let n=document.createRange().createContextualFragment(Se(e,...t));return n.children.length===1?n.children[0]:n.children},Pe=(e,...t)=>(t=t.map(n=>n instanceof HTMLCollection?[...n]:n).flat(1/0).filter(n=>n),e.append(...t),e),Ft=e=>{for(;e.firstChild&&e.removeChild(e.firstChild););return e},Ht=e=>{let t=ke``;return Pe(document.head,t),t},It=async e=>{try{await navigator.clipboard.writeText(e)}catch{let t=document.createElement("textarea");t.value=e,t.setAttribute("readonly",""),t.style.position="absolute",t.style.left="-9999px",document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t)}},Vt=()=>navigator.clipboard.readText(),Ce=(e,t)=>{if(document.activeElement.nodeName==="INPUT"&&!t.listenInInput)return;let r={metaKey:["meta","os","win","cmd","command"],ctrlKey:["ctrl","control"],shiftKey:["shift"],altKey:["alt"]};if(!!t.keys.every(c=>{c=c.toLowerCase();for(let a in r)if(r[a].includes(c)&&e[a])return r[a]=[],!0;if(c==="space"&&(c=" "),c==="plus"&&(c="+"),c===e.key.toLowerCase())return!0})){for(let c in r){let a=e[c],i=r[c].length>0;if(a&&i)return}t.callback(e)}},Kt=(e,t,{listenInInput:n=!1,keydown:r=!1}={})=>{typeof e=="string"&&(e=e.split("+")),S.push({keys:e,callback:t,listenInInput:n,keydown:r}),Le||(Le=!0,document.addEventListener("keyup",s=>{for(let c of S.filter(({keydown:a})=>!a))Ce(s,c)}),document.addEventListener("keydown",s=>{for(let c of S.filter(({keydown:a})=>a))Ce(s,c)}))},Xt=e=>{S=S.filter(t=>t.callback!==e)},Gt=(e,t=[])=>{if(!te){let n=r=>{for(;r.length;){let s=r.shift(),c=(i,d)=>i instanceof Element&&(i.matches(d)||i.matches(`${d} *`)||i.querySelector(d)),a=i=>s.target.matches(i)||s.target.matches(`${i} *`)||[...s.addedNodes].some(d=>c(d,i));for(let i of W)(!i.selectors.length||i.selectors.some(a))&&i.callback(s)}};te=new MutationObserver((r,s)=>{ne.length||requestIdleCallback(()=>n(ne)),ne.push(...r)}),te.observe(document.body,{childList:!0,subtree:!0,attributes:!0})}W.push({callback:e,selectors:t})},Qt=e=>{W=W.filter(t=>t.callback!==e)};var R={};y(R,{addCornerAction:()=>Ke,addPanelView:()=>Ie,addTooltip:()=>Ne,feather:()=>Re});"use strict";var Oe,p,Yt=e=>[...e.getClientRects()].reduce((t,n)=>t.some(r=>r.y===n.y)?t:[...t,n],[]).length,Dt=async(e,t,n)=>{p.style.top="0px",p.style.left="0px";let r=e.getBoundingClientRect(),{offsetWidth:s,offsetHeight:c}=p,a=6,i=r.x,d=Math.floor(r.y);if(["top","bottom"].includes(t)){t==="top"&&(d-=c+a),t==="bottom"&&(d+=r.height+a),i-=s/2-r.width/2,p.style.left=`${i}px`,p.style.top=`${d}px`;let x=()=>Yt(p.firstElementChild)>n,A=x();for(;x();)p.style.left=`${window.innerWidth-i>i?i++:i--}px`;A&&(i+=window.innerWidth-i>i?a:-a,p.style.left=`${i}px`),p.style.textAlign="center"}return["left","right"].includes(t)&&(d-=c/2-r.height/2,t==="left"&&(i-=s+a),t==="right"&&(i+=r.width+a),p.style.left=`${i}px`,p.style.top=`${d}px`,p.style.textAlign="start"),!0},Ne=async(e,t,{delay:n=100,offsetDirection:r="bottom",maxLines:s=1}={})=>{Oe||(Oe=o.loadStylesheet("api/components/tooltip.css"),p=o.html`
`,o.render(document.body,p)),globalThis.markdownit||await import(u.localPath("dep/markdown-it.min.js"));let c=markdownit({linkify:!0});t instanceof Element||(t=o.html`
- ${t.split(` -`).map(i=>c.renderInline(i)).join("
")} -
`);let a;e.addEventListener("mouseover",async i=>{a||(a=setTimeout(async()=>{e.matches(":hover")&&p.style.display!=="block"&&(p.style.display="block",o.render(o.empty(p),t),Dt(e,r,s),await p.animate([{opacity:0},{opacity:1}],{duration:65}).finished),a=void 0},n))}),e.addEventListener("mouseout",async i=>{a=void 0,p.style.display==="block"&&!e.matches(":hover")&&(await p.animate([{opacity:1},{opacity:0}],{duration:65}).finished,p.style.display="")})};"use strict";var re,Re=async(e,t={})=>(re||(re=o.html`${await u.getText("dep/feather-sprite.svg")}`),t.style=((t.style?t.style+";":"")+"stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;fill:none;").trim(),t.viewBox="0 0 24 24",``${o.escape(n)}="${o.escape(r)}"`).join(" ")}>${re.getElementById(e)?.innerHTML}`);"use strict";var k=[],en=o.raw` - - `,qe,v,z,w,$,P,E,Me,Je,se,f,We,U,C,Z,oe,b,ie,O,B="data-enhancer-panel-pinned",F=()=>$.hasAttribute(B),N=()=>{let e=[z,w,P,$].filter(t=>t);if(F()){ae();for(let t of e)t.removeAttribute(B)}else for(let t of e)t.setAttribute(B,"true");v.set(["panel.pinned"],F())},ze=async()=>{document.documentElement.style.setProperty("--component--panel-width",f+"px"),v.set(["panel.width"],f)},Ue=e=>{e.preventDefault(),se=!0,f=Je+(Me-e.clientX),f<190&&(f=190),f>480&&(f=480),$.style.width=f+"px",P.style.width=f+"px",z.style.paddingRight=f+"px",w&&(w.style.right=f+"px")},Ze=e=>{$.style.width="",P.style.width="",z.style.paddingRight="",w&&(w.style.right=""),ze(),E.style.cursor="",document.body.removeEventListener("mousemove",Ue),document.body.removeEventListener("mouseup",Ze)},tn=e=>{Me=e.clientX,Je=f,E.style.cursor="auto",document.body.addEventListener("mousemove",Ue),document.body.addEventListener("mouseup",Ze)},nn=()=>document.body.contains(b),Be=()=>{if(!F())return N();o.render(We,O),o.empty(b);for(let t of k){let n=C.contains(t.$title),r=o.render(o.html`
`,o.render(o.html``,t.$icon.cloneNode(!0),t.$title.cloneNode(!0)));r.addEventListener("click",()=>{He(t),v.set(["panel.open"],t.id)}),o.render(b,r)}let e=Z.getBoundingClientRect();o.render(o.empty(O),o.render(o.html`
`,o.render(o.html`
`,b))),b.querySelector("[data-open]").focus(),b.animate([{opacity:0},{opacity:1}],{duration:200}),document.addEventListener("keydown",Fe)},ae=()=>{document.removeEventListener("keydown",Fe),b.animate([{opacity:1},{opacity:0}],{duration:200}).onfinish=()=>O.remove()},Fe=e=>{if(nn())switch(e.key){case"Escape":ae(),e.stopPropagation();break;case"Enter":document.activeElement.click(),e.stopPropagation();break;case"ArrowUp":(e.target.previousElementSibling||e.target.parentElement.lastElementChild).focus(),e.stopPropagation();break;case"ArrowDown":(e.target.nextElementSibling||e.target.parentElement.firstElementChild).focus(),e.stopPropagation();break}},He=e=>{let t=k.find(({$content:n})=>document.contains(n));o.render(o.empty(C),o.render(o.html``,e.$icon,e.$title)),e.onFocus(),o.render(o.empty(oe),e.$content),t&&t.onBlur()};async function rn(){await o.whenReady([".notion-frame"]),z=document.querySelector(".notion-frame"),$=o.html`
`,P=o.html`
`,E=o.html`
`,C=o.html`
`,Z=o.render(o.html`
`,C),oe=o.html`
`,b=o.html`
`,ie=o.html`
- ${en} -
`,O=o.html`
`;let e='.notion-cursor-listener > div[style*="flex-end"]',t=()=>{document.contains(w)||(w=document.querySelector(e),F()&&w&&w.setAttribute(B,"true"))};w=document.querySelector(e),o.addDocumentObserver(t,[e]),await v.get(["panel.pinned"])&&N(),o.addHotkeyListener(await v.get(["panel.hotkey"]),N),U.addEventListener("click",r=>{r.stopPropagation(),N()}),o.render($,o.render(Z,C,ie,U),oe,E),await sn(),await on();let n='.notion-cursor-listener > .notion-sidebar-container ~ [style^="position: absolute"]';await o.whenReady([n]),document.querySelector(n).before(P,$)}async function sn(){f=await v.get(["panel.width"],240),ze(),E.addEventListener("mousedown",tn),E.addEventListener("click",()=>{se?se=!1:N()})}async function on(){We=document.querySelector(".notion-app-inner"),Z.addEventListener("click",Be),ie.addEventListener("click",Be),O.addEventListener("click",ae)}var Ie=async({id:e,icon:t,title:n,$content:r,onFocus:s=()=>{},onBlur:c=()=>{}})=>{qe||(qe=o.loadStylesheet("api/components/panel.css")),v||(v=await g.db("36a2ffc9-27ff-480e-84a7-c7700a7d232d")),U||(U=o.html`
- ${await R.feather("chevrons-right")} -
`);let a={id:e,$icon:o.render(o.html``,t instanceof Element?t:o.html`${t}`),$title:o.render(o.html``,n),$content:r,onFocus:s,onBlur:c};k.push(a),k.length===1&&await rn(),(k.length===1||await v.get(["panel.open"])===e)&&He(a)};"use strict";var Ve,q,Ke=async(e,t)=>{Ve||(Ve=o.loadStylesheet("api/components/corner-action.css"),q=o.html`
`),await o.whenReady([".notion-help-button"]);let n=document.querySelector(".notion-help-button"),r=document.querySelector(".onboarding-checklist-button");r&&q.prepend(r),q.prepend(n),o.render(document.querySelector(".notion-app-inner > .notion-cursor-listener"),q);let s=o.html`
${e}
`;return s.addEventListener("click",t),o.render(q,s),s};"use strict";"use strict"; diff --git a/src/common/index.mjs b/src/common/index.mjs deleted file mode 100644 index f3538f8..0000000 --- a/src/common/index.mjs +++ /dev/null @@ -1,31 +0,0 @@ -/** - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -// compiles to .cjs for use in electron: -// npx -y esbuild insert/api/index.mjs --minify --bundle --format=cjs --outfile=insert/api/index.cjs - -/** environment-specific methods and constants */ -export * as env from './env.mjs'; -/** environment-specific file reading */ -export * as fs from './fs.mjs'; -/** environment-specific data persistence */ -export * as storage from './storage.mjs'; - -/** access to electron renderer apis */ -export * as electron from './electron.mjs'; - -/** a basic wrapper around notion's unofficial api */ -export * as notion from './notion.mjs'; -/** helpers for formatting, validating and parsing values */ -export * as fmt from './fmt.mjs'; -/** interactions with the enhancer's repository of mods */ -export * as registry from './registry.mjs'; -/** helpers for manipulation of a webpage */ -export * as web from './web.mjs'; -/** shared notion-style elements */ -export * as components from './components/index.mjs'; diff --git a/src/common/registry-validation.mjs b/src/common/registry-validation.mjs deleted file mode 100644 index 1b032d2..0000000 --- a/src/common/registry-validation.mjs +++ /dev/null @@ -1,224 +0,0 @@ -/** - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -import { fmt, registry } from './index.mjs'; - -const check = async ( - mod, - key, - value, - types, - { - extension = '', - error = `invalid ${key} (${extension ? `${extension} ` : ''}${types}): ${JSON.stringify( - value - )}`, - optional = false, - } = {} -) => { - let test; - for (const type of Array.isArray(types) ? [types] : types.split('|')) { - if (type === 'file') { - test = - value && !value.startsWith('http') - ? await fmt.is(`repo/${mod._dir}/${value}`, type, { extension }) - : false; - } else test = await fmt.is(value, type, { extension }); - if (test) break; - } - if (!test) { - if (optional && (await fmt.is(value, 'undefined'))) return true; - if (error) mod._err(error); - return false; - } - return true; -}; - -const validateEnvironments = async (mod) => { - mod.environments = mod.environments ?? registry.supportedEnvs; - const isArray = await check(mod, 'environments', mod.environments, 'array'); - if (!isArray) return false; - return mod.environments.map((tag) => - check(mod, 'environments.env', tag, registry.supportedEnvs) - ); - }, - validateTags = async (mod) => { - const isArray = await check(mod, 'tags', mod.tags, 'array'); - if (!isArray) return false; - const categoryTags = ['core', 'extension', 'theme', 'integration'], - containsCategory = mod.tags.filter((tag) => categoryTags.includes(tag)).length; - if (!containsCategory) { - mod._err( - `invalid tags (must contain at least one of 'core', 'extension', 'theme' or 'integration'): - ${JSON.stringify(mod.tags)}` - ); - return false; - } - const isTheme = mod.tags.includes('theme'), - hasThemeMode = mod.tags.includes('light') || mod.tags.includes('dark'), - isBothThemeModes = mod.tags.includes('light') && mod.tags.includes('dark'); - if (isTheme && (!hasThemeMode || isBothThemeModes)) { - mod._err( - `invalid tags (themes must be either 'light' or 'dark', not neither or both): - ${JSON.stringify(mod.tags)}` - ); - return false; - } - return mod.tags.map((tag) => check(mod, 'tags.tag', tag, 'string')); - }, - validateAuthors = async (mod) => { - const isArray = await check(mod, 'authors', mod.authors, 'array'); - if (!isArray) return false; - return mod.authors.map((author) => [ - check(mod, 'authors.author.name', author.name, 'string'), - check(mod, 'authors.author.email', author.email, 'email', { optional: true }), - check(mod, 'authors.author.homepage', author.homepage, 'url'), - check(mod, 'authors.author.avatar', author.avatar, 'url'), - ]); - }, - validateCSS = async (mod) => { - const isArray = await check(mod, 'css', mod.css, 'object'); - if (!isArray) return false; - const tests = []; - for (const dest of ['frame', 'client', 'menu']) { - if (!mod.css[dest]) continue; - let test = await check(mod, `css.${dest}`, mod.css[dest], 'array'); - if (test) { - test = mod.css[dest].map((file) => - check(mod, `css.${dest}.file`, file, 'file', { extension: '.css' }) - ); - } - tests.push(test); - } - return tests; - }, - validateJS = async (mod) => { - const isArray = await check(mod, 'js', mod.js, 'object'); - if (!isArray) return false; - const tests = []; - for (const dest of ['frame', 'client', 'menu']) { - if (!mod.js[dest]) continue; - let test = await check(mod, `js.${dest}`, mod.js[dest], 'array'); - if (test) { - test = mod.js[dest].map((file) => - check(mod, `js.${dest}.file`, file, 'file', { extension: '.mjs' }) - ); - } - tests.push(test); - } - if (mod.js.electron) { - const isArray = await check(mod, 'js.electron', mod.js.electron, 'array'); - if (isArray) { - for (const file of mod.js.electron) { - const isObject = await check(mod, 'js.electron.file', file, 'object'); - if (!isObject) { - tests.push(false); - continue; - } - tests.push([ - check(mod, 'js.electron.file.source', file.source, 'file', { - extension: '.cjs', - }), - // referencing the file within the electron app - // existence can't be validated, so only format is - check(mod, 'js.electron.file.target', file.target, 'string', { - extension: '.js', - }), - ]); - } - } else tests.push(false); - } - return tests; - }, - validateOptions = async (mod) => { - const isArray = await check(mod, 'options', mod.options, 'array'); - if (!isArray) return false; - const tests = []; - for (const option of mod.options) { - const key = 'options.option', - optTypeValid = await check(mod, `${key}.type`, option.type, registry.optionTypes); - if (!optTypeValid) { - tests.push(false); - continue; - } - option.environments = option.environments ?? registry.supportedEnvs; - tests.push([ - check(mod, `${key}.key`, option.key, 'alphanumeric'), - check(mod, `${key}.label`, option.label, 'string'), - check(mod, `${key}.tooltip`, option.tooltip, 'string', { - optional: true, - }), - check(mod, `${key}.environments`, option.environments, 'array').then((isArray) => { - if (!isArray) return false; - return option.environments.map((environment) => - check(mod, `${key}.environments.env`, environment, registry.supportedEnvs) - ); - }), - ]); - switch (option.type) { - case 'toggle': - tests.push(check(mod, `${key}.value`, option.value, 'boolean')); - break; - case 'select': { - let test = await check(mod, `${key}.values`, option.values, 'array'); - if (test) { - test = option.values.map((value) => - check(mod, `${key}.values.value`, value, 'string') - ); - } - tests.push(test); - break; - } - case 'text': - case 'hotkey': - tests.push(check(mod, `${key}.value`, option.value, 'string')); - break; - case 'number': - case 'color': - tests.push(check(mod, `${key}.value`, option.value, option.type)); - break; - case 'file': { - let test = await check(mod, `${key}.extensions`, option.extensions, 'array'); - if (test) { - test = option.extensions.map((ext) => - check(mod, `${key}.extensions.extension`, ext, 'string') - ); - } - tests.push(test); - break; - } - } - } - return tests; - }; - -/** - * internally used to validate mod.json files and provide helpful errors - * @private - * @param {object} mod - a mod's mod.json in object form - * @returns {boolean} whether or not the mod has passed validation - */ -export async function validate(mod) { - let conditions = [ - check(mod, 'name', mod.name, 'string'), - check(mod, 'id', mod.id, 'uuid'), - check(mod, 'version', mod.version, 'semver'), - validateEnvironments(mod), - check(mod, 'description', mod.description, 'string'), - check(mod, 'preview', mod.preview, 'file|url', { optional: true }), - validateTags(mod), - validateAuthors(mod), - validateCSS(mod), - validateJS(mod), - validateOptions(mod), - ]; - do { - conditions = await Promise.all(conditions.flat(Infinity)); - } while (conditions.some((condition) => Array.isArray(condition))); - return conditions.every((passed) => passed); -} diff --git a/src/common/registry.js b/src/common/registry.js new file mode 100644 index 0000000..6ca5404 --- /dev/null +++ b/src/common/registry.js @@ -0,0 +1,67 @@ +/** + * notion-enhancer + * (c) 2022 dragonwocky (https://dragonwocky.me/) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +"use strict"; + +let _core, _mods; +const getCore = () => { + _core ??= globalThis.__enhancerApi.readJson("/core/mod.json"); + return _core; + }, + getMods = async () => { + const { readJson } = globalThis.__enhancerApi; + _mods ??= await Promise.all([ + getCore(), + // prettier-ignore + ...(await readJson("/mods/registry.json")).map(async (modFolder) => { + try { + modFolder = `/mods/${modFolder}/mod.json`; + const modManifest = await readJson(modFolder); + modManifest._src = modFolder; + return modManifest; + } catch {} + }), + ]).filter((mod) => mod); + return _mods; + }, + getThemes = async () => { + const mods = await getMods(); + return mods.filter(({ tags }) => tags.includes("theme")); + }, + getExtensions = async () => { + const mods = await getMods(); + return mods.filter(({ tags }) => tags.includes("extension")); + }, + getIntegrations = async () => { + const mods = await getMods(); + return mods.filter(({ tags }) => tags.includes("integration")); + }; + +const getProfile = async () => { + const { initDatabase } = globalThis.__enhancerApi, + currentProfile = await initDatabase().get("currentProfile"); + return currentProfile ?? "default"; + }, + isEnabled = async (id) => { + if (id === (await getCore()).id) return true; + const { platform } = globalThis.__enhancerApi, + mod = (await getMods()).find((mod) => mod.id === id); + if (mod.platforms && !mod.platforms.includes(platform)) return false; + const { initDatabase } = globalThis.__enhancerApi, + enabledMods = await initDatabase([await getProfile(), "enabledMods"]); + return Boolean(enabledMods.get(id)); + }; + +globalThis.__enhancerApi ??= {}; +Object.assign(globalThis.__enhancerApi, { + getMods, + getCore, + getThemes, + getExtensions, + getIntegrations, + getProfile, + isEnabled, +}); diff --git a/src/common/registry.mjs b/src/common/registry.mjs deleted file mode 100644 index 4c2682b..0000000 --- a/src/common/registry.mjs +++ /dev/null @@ -1,160 +0,0 @@ -/** - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** - * interactions with the enhancer's repository of mods - * @namespace registry - */ - -import { env, fs, storage } from './index.mjs'; -import { validate } from './registry-validation.mjs'; - -/** - * mod ids whitelisted as part of the enhancer's core, permanently enabled - * @constant - * @type {string[]} - */ -export const core = [ - 'a6621988-551d-495a-97d8-3c568bca2e9e', - '0f0bf8b6-eae6-4273-b307-8fc43f2ee082', - '36a2ffc9-27ff-480e-84a7-c7700a7d232d', -]; - -/** - * all environments/platforms currently supported by the enhancer - * @constant - * @type {string[]} - */ -export const supportedEnvs = ['linux', 'win32', 'darwin', 'extension']; - -/** - * all available configuration types - * @constant - * @type {string[]} - */ -export const optionTypes = ['toggle', 'select', 'text', 'number', 'color', 'file', 'hotkey']; - -/** - * the name of the active configuration profile - * @returns {string} - */ -export const profileName = () => storage.get(['currentprofile'], 'default'); - -/** - * the root database for the current profile - * @returns {object} the get/set functions for the profile's storage - */ -export const profileDB = async () => storage.db(['profiles', await profileName()]); - -let _list; -const _errors = []; -/** - * list all available mods in the repo - * @param {function} filter - a function to filter out mods - * @returns {array} a validated list of mod.json objects - */ -export const list = async (filter = (mod) => true) => { - if (!_list) { - // deno-lint-ignore no-async-promise-executor - _list = new Promise(async (res, _rej) => { - const passed = []; - for (const dir of await fs.getJSON('repo/registry.json')) { - try { - const mod = { - ...(await fs.getJSON(`repo/${dir}/mod.json`)), - _dir: dir, - _err: (message) => _errors.push({ source: dir, message }), - }; - if (await validate(mod)) passed.push(mod); - } catch { - _errors.push({ source: dir, message: 'invalid mod.json' }); - } - } - res(passed); - }); - } - const filtered = []; - for (const mod of await _list) if (await filter(mod)) filtered.push(mod); - return filtered; -}; - -/** - * list validation errors encountered when loading the repo - * @returns {{ source: string, message: string }[]} error objects with an error message and a source directory - */ -export const errors = async () => { - await list(); - return _errors; -}; - -/** - * get a single mod from the repo - * @param {string} id - the uuid of the mod - * @returns {object} the mod's mod.json - */ -export const get = async (id) => { - return (await list((mod) => mod.id === id))[0]; -}; - -/** - * checks if a mod is enabled: affected by the core whitelist, - * environment and menu configuration - * @param {string} id - the uuid of the mod - * @returns {boolean} whether or not the mod is enabled - */ -export const enabled = async (id) => { - const mod = await get(id); - if (!mod.environments.includes(env.name)) return false; - if (core.includes(id)) return true; - return (await profileDB()).get(['_mods', id], false); -}; - -/** - * get a default value of a mod's option according to its mod.json - * @param {string} id - the uuid of the mod - * @param {string} key - the key of the option - * @returns {string|number|boolean|undefined} the option's default value - */ -export const optionDefault = async (id, key) => { - const mod = await get(id), - opt = mod.options.find((opt) => opt.key === key); - if (!opt) return undefined; - switch (opt.type) { - case 'toggle': - case 'text': - case 'number': - case 'color': - case 'hotkey': - return opt.value; - case 'select': - return opt.values[0]; - case 'file': - return undefined; - } -}; - -/** - * access the storage partition of a mod in the current profile - * @param {string} id - the uuid of the mod - * @returns {object} an object with the wrapped get/set functions - */ -export const db = async (id) => { - const db = await profileDB(); - return storage.db( - [id], - async (path, fallback = undefined) => { - if (typeof path === 'string') path = [path]; - if (path.length === 2) { - // profiles -> profile -> mod -> option - fallback = (await optionDefault(id, path[1])) ?? fallback; - } - return db.get(path, fallback); - }, - db.set - ); -}; diff --git a/src/common/storage.mjs b/src/common/storage.mjs deleted file mode 100644 index 8c7dc31..0000000 --- a/src/common/storage.mjs +++ /dev/null @@ -1,65 +0,0 @@ -/** - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** - * environment-specific data persistence - * @namespace storage - */ - -import * as storage from '../env/storage.mjs'; - -/** - * get persisted data - * @type {function} - * @param {string[]} path - the path of keys to the value being fetched - * @param {unknown=} fallback - a default value if the path is not matched - * @returns {Promise} value ?? fallback - */ -export const get = storage.get; - -/** - * persist data - * @type {function} - * @param {string[]} path - the path of keys to the value being set - * @param {unknown} value - the data to save - * @returns {Promise} resolves when data has been saved - */ -export const set = storage.set; - -/** - * create a wrapper for accessing a partition of the storage - * @type {function} - * @param {string[]} namespace - the path of keys to prefix all storage requests with - * @param {function=} get - the storage get function to be wrapped - * @param {function=} set - the storage set function to be wrapped - * @returns {object} an object with the wrapped get/set functions - */ -export const db = storage.db; - -/** - * add an event listener for changes in storage - * @type {function} - * @param {onStorageChangeCallback} callback - called whenever a change in - * storage is initiated from the current process - */ -export const addChangeListener = storage.addChangeListener; - -/** - * remove a listener added with storage.addChangeListener - * @type {function} - * @param {onStorageChangeCallback} callback - */ -export const removeChangeListener = storage.removeChangeListener; - -/** - * @callback onStorageChangeCallback - * @param {object} event - * @param {string} event.path- the path of keys to the changed value - * @param {string=} event.new - the new value being persisted to the store - * @param {string=} event.old - the previous value associated with the key - */ diff --git a/src/common/web.mjs b/src/common/utils.js similarity index 76% rename from src/common/web.mjs rename to src/common/utils.js index 8b201e0..36b6cd8 100644 --- a/src/common/web.mjs +++ b/src/common/utils.js @@ -4,14 +4,45 @@ * (https://notion-enhancer.github.io/) under the MIT license */ -'use strict'; +/** + * log-based shading of an rgb color, from + * https://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors + * @param {number} shade - a decimal amount to shade the color. + * 1 = white, 0 = the original color, -1 = black + * @param {string} color - the rgb color + * @returns {string} the shaded color + */ +export const rgbLogShade = (shade, color) => { + const int = parseInt, + round = Math.round, + [a, b, c, d] = color.split(","), + t = shade < 0 ? 0 : shade * 255 ** 2, + p = shade < 0 ? 1 + shade : 1 - shade; + return ( + "rgb" + + (d ? "a(" : "(") + + round((p * int(a[3] == "a" ? a.slice(5) : a.slice(4)) ** 2 + t) ** 0.5) + + "," + + round((p * int(b) ** 2 + t) ** 0.5) + + "," + + round((p * int(c) ** 2 + t) ** 0.5) + + (d ? "," + d : ")") + ); +}; /** - * helpers for manipulation of a webpage - * @namespace web + * pick a contrasting color e.g. for text on a variable color background + * using the hsp (perceived brightness) constants from http://alienryderflex.com/hsp.html + * @param {number} r - red (0-255) + * @param {number} g - green (0-255) + * @param {number} b - blue (0-255) + * @returns {string} the contrasting rgb color, white or black */ - -import { fs } from './index.mjs'; +export const rgbContrast = (r, g, b) => { + return Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b)) > 165.75 + ? "rgb(0,0,0)" + : "rgb(255,255,255)"; +}; let _hotkeyListenersActivated = false, _hotkeyEventListeners = [], @@ -36,9 +67,9 @@ export const whenReady = (selectors = []) => { } isReady(); }; - if (document.readyState !== 'complete') { - document.addEventListener('readystatechange', (_event) => { - if (document.readyState === 'complete') onLoad(); + if (document.readyState !== "complete") { + document.addEventListener("readystatechange", (_event) => { + if (document.readyState === "complete") onLoad(); }); } else onLoad(); }); @@ -57,12 +88,12 @@ export const queryParams = () => new URLSearchParams(window.location.search); */ export const escape = (str) => str - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/'/g, ''') - .replace(/"/g, '"') - .replace(/\\/g, '\'); + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/'/g, "'") + .replace(/"/g, """) + .replace(/\\/g, "\"); /** * a tagged template processor for raw html: @@ -75,18 +106,18 @@ export const raw = (str, ...templates) => { .map( (chunk) => chunk + - (['string', 'number'].includes(typeof templates[0]) + (["string", "number"].includes(typeof templates[0]) ? templates.shift() - : escape(JSON.stringify(templates.shift(), null, 2) ?? '')) + : escape(JSON.stringify(templates.shift(), null, 2) ?? "")) ) - .join(''); - return html.includes(' line.trim()) .filter((line) => line.length) - .join(' '); + .join(" "); }; /** @@ -131,7 +162,7 @@ export const empty = ($container) => { export const loadStylesheet = (path) => { const $stylesheet = html``; render(document.head, $stylesheet); return $stylesheet; @@ -146,14 +177,14 @@ export const copyToClipboard = async (str) => { try { await navigator.clipboard.writeText(str); } catch { - const $el = document.createElement('textarea'); + const $el = document.createElement("textarea"); $el.value = str; - $el.setAttribute('readonly', ''); - $el.style.position = 'absolute'; - $el.style.left = '-9999px'; + $el.setAttribute("readonly", ""); + $el.style.position = "absolute"; + $el.style.left = "-9999px"; document.body.appendChild($el); $el.select(); - document.execCommand('copy'); + document.execCommand("copy"); document.body.removeChild($el); } }; @@ -167,13 +198,13 @@ export const readFromClipboard = () => { }; const triggerHotkeyListener = (event, hotkey) => { - const inInput = document.activeElement.nodeName === 'INPUT' && !hotkey.listenInInput; + const inInput = document.activeElement.nodeName === "INPUT" && !hotkey.listenInInput; if (inInput) return; const modifiers = { - metaKey: ['meta', 'os', 'win', 'cmd', 'command'], - ctrlKey: ['ctrl', 'control'], - shiftKey: ['shift'], - altKey: ['alt'], + metaKey: ["meta", "os", "win", "cmd", "command"], + ctrlKey: ["ctrl", "control"], + shiftKey: ["shift"], + altKey: ["alt"], }, pressed = hotkey.keys.every((key) => { key = key.toLowerCase(); @@ -185,8 +216,8 @@ const triggerHotkeyListener = (event, hotkey) => { return true; } } - if (key === 'space') key = ' '; - if (key === 'plus') key = '+'; + if (key === "space") key = " "; + if (key === "plus") key = "+"; if (key === event.key.toLowerCase()) return true; }); if (!pressed) return; @@ -218,17 +249,17 @@ export const addHotkeyListener = ( callback, { listenInInput = false, keydown = false } = {} ) => { - if (typeof keys === 'string') keys = keys.split('+'); + if (typeof keys === "string") keys = keys.split("+"); _hotkeyEventListeners.push({ keys, callback, listenInInput, keydown }); if (!_hotkeyListenersActivated) { _hotkeyListenersActivated = true; - document.addEventListener('keyup', (event) => { + document.addEventListener("keyup", (event) => { for (const hotkey of _hotkeyEventListeners.filter(({ keydown }) => !keydown)) { triggerHotkeyListener(event, hotkey); } }); - document.addEventListener('keydown', (event) => { + document.addEventListener("keydown", (event) => { for (const hotkey of _hotkeyEventListeners.filter(({ keydown }) => keydown)) { triggerHotkeyListener(event, hotkey); } diff --git a/src/mods/components/mod.json b/src/core/components/mod.json similarity index 100% rename from src/mods/components/mod.json rename to src/core/components/mod.json diff --git a/src/mods/menu/client.css b/src/core/menu/client.css similarity index 100% rename from src/mods/menu/client.css rename to src/core/menu/client.css diff --git a/src/mods/menu/client.mjs b/src/core/menu/client.mjs similarity index 100% rename from src/mods/menu/client.mjs rename to src/core/menu/client.mjs diff --git a/src/mods/menu/components.mjs b/src/core/menu/components.mjs similarity index 100% rename from src/mods/menu/components.mjs rename to src/core/menu/components.mjs diff --git a/src/mods/menu/markdown.css b/src/core/menu/markdown.css similarity index 100% rename from src/mods/menu/markdown.css rename to src/core/menu/markdown.css diff --git a/src/mods/menu/menu.css b/src/core/menu/menu.css similarity index 100% rename from src/mods/menu/menu.css rename to src/core/menu/menu.css diff --git a/src/mods/menu/menu.html b/src/core/menu/menu.html similarity index 100% rename from src/mods/menu/menu.html rename to src/core/menu/menu.html diff --git a/src/mods/menu/menu.mjs b/src/core/menu/menu.mjs similarity index 100% rename from src/mods/menu/menu.mjs rename to src/core/menu/menu.mjs diff --git a/src/mods/menu/mod.json b/src/core/menu/mod.json similarity index 100% rename from src/mods/menu/mod.json rename to src/core/menu/mod.json diff --git a/src/mods/menu/notifications.mjs b/src/core/menu/notifications.mjs similarity index 100% rename from src/mods/menu/notifications.mjs rename to src/core/menu/notifications.mjs diff --git a/src/mods/menu/router.mjs b/src/core/menu/router.mjs similarity index 100% rename from src/mods/menu/router.mjs rename to src/core/menu/router.mjs diff --git a/src/mods/menu/styles.mjs b/src/core/menu/styles.mjs similarity index 100% rename from src/mods/menu/styles.mjs rename to src/core/menu/styles.mjs diff --git a/src/core/mod.json b/src/core/mod.json new file mode 100644 index 0000000..13f4edd --- /dev/null +++ b/src/core/mod.json @@ -0,0 +1,44 @@ +{ + "id": "0f0bf8b6-eae6-4273-b307-8fc43f2ee082", + "name": "notion-enhancer", + "version": "0.11.1-dev", + "description": "an enhancer/customiser for the all-in-one productivity workspace notion.so", + "tags": ["core"], + "authors": [ + { + "name": "dragonwocky", + "homepage": "https://dragonwocky.me/", + "avatar": "https://dragonwocky.me/avatar.jpg" + } + ], + "options": [ + { + "type": "heading", + "label": "Hotkeys" + }, + { + "type": "hotkey", + "key": "openMenuHotkey", + "description": "Opens the notion-enhancer menu from within Notion.", + "value": "CmdOrCtrl+Shift+," + }, + { + "type": "heading", + "label": "Appearance" + }, + { + "type": "toggle", + "key": "loadThemeOverrides", + "description": "Loads the styling required for a theme to customise Notion's interface. Turning this off will disable all themes but may increase client performance.", + "value": true + }, + { + "type": "file", + "key": "customStyles", + "description": "Adds the styles from an uploaded .css file to Notion. Use this if you would like to customise the current theme or otherwise tweak Notion's appearance." + } + ], + "clientStyles": [], + "clientScripts": [], + "electronScripts": {} +} diff --git a/src/mods/theming/_mapColors.js b/src/core/theming/_mapColors.js similarity index 100% rename from src/mods/theming/_mapColors.js rename to src/core/theming/_mapColors.js diff --git a/src/mods/theming/client.mjs b/src/core/theming/client.mjs similarity index 100% rename from src/mods/theming/client.mjs rename to src/core/theming/client.mjs diff --git a/src/mods/theming/colors.css b/src/core/theming/colors.css similarity index 100% rename from src/mods/theming/colors.css rename to src/core/theming/colors.css diff --git a/src/mods/theming/electronSearch.css b/src/core/theming/electronSearch.css similarity index 100% rename from src/mods/theming/electronSearch.css rename to src/core/theming/electronSearch.css diff --git a/src/mods/theming/frame.mjs b/src/core/theming/frame.mjs similarity index 100% rename from src/mods/theming/frame.mjs rename to src/core/theming/frame.mjs diff --git a/src/mods/theming/main.cjs b/src/core/theming/main.cjs similarity index 100% rename from src/mods/theming/main.cjs rename to src/core/theming/main.cjs diff --git a/src/mods/theming/menu.mjs b/src/core/theming/menu.mjs similarity index 100% rename from src/mods/theming/menu.mjs rename to src/core/theming/menu.mjs diff --git a/src/mods/theming/mod.json b/src/core/theming/mod.json similarity index 100% rename from src/mods/theming/mod.json rename to src/core/theming/mod.json diff --git a/src/mods/theming/patches.css b/src/core/theming/patches.css similarity index 100% rename from src/mods/theming/patches.css rename to src/core/theming/patches.css diff --git a/src/mods/theming/prism.css b/src/core/theming/prism.css similarity index 100% rename from src/mods/theming/prism.css rename to src/core/theming/prism.css diff --git a/src/mods/theming/rendererSearch.cjs b/src/core/theming/rendererSearch.cjs similarity index 100% rename from src/mods/theming/rendererSearch.cjs rename to src/core/theming/rendererSearch.cjs diff --git a/src/mods/theming/theme.css b/src/core/theming/theme.css similarity index 100% rename from src/mods/theming/theme.css rename to src/core/theming/theme.css diff --git a/src/mods/theming/variables.css b/src/core/theming/variables.css similarity index 100% rename from src/mods/theming/variables.css rename to src/core/theming/variables.css diff --git a/src/mods/tweaks/client.css b/src/core/tweaks/client.css similarity index 100% rename from src/mods/tweaks/client.css rename to src/core/tweaks/client.css diff --git a/src/mods/tweaks/client.mjs b/src/core/tweaks/client.mjs similarity index 100% rename from src/mods/tweaks/client.mjs rename to src/core/tweaks/client.mjs diff --git a/src/mods/tweaks/mod.json b/src/core/tweaks/mod.json similarity index 100% rename from src/mods/tweaks/mod.json rename to src/core/tweaks/mod.json diff --git a/src/electron/api.js b/src/electron/api.js new file mode 100644 index 0000000..7baab36 --- /dev/null +++ b/src/electron/api.js @@ -0,0 +1,109 @@ +/** + * notion-enhancer + * (c) 2022 dragonwocky (https://dragonwocky.me/) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +"use strict"; + +const fs = require("fs"), + os = require("os"), + path = require("path"), + platform = process.platform; + +const notionRequire = (target) => require(`../../../${target}`), + notionPath = (target) => path.resolve(`${__dirname}/../../../${target}`); + +const enhancerRequire = (target) => require(`../${target}`), + enhancerPath = (target) => path.resolve(`${__dirname}/../${target}`), + enhancerUrl = (target) => + `notion://www.notion.so/__notion-enhancer/${target}`, + enhancerVersion = enhancerRequire("package.json").version, + enhancerConfig = path.resolve(`${os.homedir()}/.notion-enhancer.db`); + +const readFile = (file) => { + // prettier-ignore + file = file.replace(/^https:\/\/www\.notion\.so\//, "notion://www.notion.so/"); + const useFetch = file.startsWith("http") || file.startsWith("notion://"); + if (useFetch) return fetch(file).then((res) => res.text()); + return fs.readFileSync(enhancerPath(file)); + }, + readJson = (file) => { + // prettier-ignore + file = file.replace(/^https:\/\/www\.notion\.so\//, "notion://www.notion.so/"); + const useFetch = file.startsWith("http") || file.startsWith("notion://"); + if (useFetch) return fetch(file).then((res) => res.json()); + return require(enhancerPath(file)); + }, + reloadApp = () => { + const { app } = require("electron"), + args = process.argv.slice(1).filter((arg) => arg !== "--startup"); + app.relaunch({ args }); + app.exit(); + }; + +let __db; +const initDatabase = (namespace) => { + if (Array.isArray(namespace)) namespace = namespace.join("__"); + namespace = namespace ? namespace + "__" : ""; + + const table = "settings", + sqlite = require("better-sqlite3"), + db = __db ?? sqlite(enhancerConfig), + init = db.prepare(`CREATE TABLE IF NOT EXISTS ${table} ( + key TEXT PRIMARY KEY, + value TEXT, + mtime INTEGER + )`); + init.run(); + __db = db; + + // prettier-ignore + const insert = db.prepare(`INSERT INTO ${table} (key, value, mtime) VALUES (?, ?, ?)`), + // prettier-ignore + update = db.prepare(`UPDATE ${table} SET value = ?, mtime = ? WHERE key = ?`), + select = db.prepare(`SELECT * FROM ${table} WHERE key = ? LIMIT 1`), + dump = db.prepare(`SELECT * FROM ${table}`), + populate = db.transaction((obj) => { + for (const key in obj) { + if (select.get(key)) update.run(value, key, Date.now()); + else insert.run(key, value, Date.now()); + } + }); + + return { + get: (key) => { + key = key.startsWith(namespace) ? key : namespace + key; + return select.get(key)?.value; + }, + set: (key, value) => { + key = key.startsWith(namespace) ? key : namespace + key; + if (select.get(key)) return update.run(value, key, Date.now()); + else return insert.run(key, value, Date.now()); + }, + dump: () => { + const rows = dump.all(); + let entries = rows.map(({ key, value }) => [key, value]); + if (!namespace) return Object.fromEntries(entries); + entries = entries.filter(([key]) => key.startsWith(`${namespace}__`)); + return Object.fromEntries(entries); + }, + populate, + }; +}; + +globalThis.__enhancerApi ??= {}; +Object.assign(globalThis.__enhancerApi, { + platform, + notionRequire, + notionPath, + enhancerRequire, + enhancerPath, + enhancerUrl, + enhancerVersion, + enhancerConfig, + readFile, + readJson, + reloadApp, + initDatabase, +}); diff --git a/src/electron/client.js b/src/electron/client.js new file mode 100644 index 0000000..5c1df9a --- /dev/null +++ b/src/electron/client.js @@ -0,0 +1,35 @@ +/** + * notion-enhancer + * (c) 2021 dragonwocky (https://dragonwocky.me/) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +"use strict"; + +console.log(123); + +(async () => { + // const { getCore, getMods, enhancerPath } = globalThis.__enhancerApi; + // console.log(await getMods()); + // const page = location.pathname.split(/[/-]/g).reverse()[0].length === 32, + // whitelisted = ["/", "/onboarding"].includes(location.pathname), + // signedIn = localStorage["LRU:KeyValueStore2:current-user-id"]; + // if (page || (whitelisted && signedIn)) { + // const api = await import("./api/index.mjs"), + // { fs, registry, web } = api; + // for (const mod of await registry.list((mod) => registry.enabled(mod.id))) { + // for (const sheet of mod.css?.client || []) { + // web.loadStylesheet(`repo/${mod._dir}/${sheet}`); + // } + // for (let script of mod.js?.client || []) { + // script = await import(fs.localPath(`repo/${mod._dir}/${script}`)); + // script.default(api, await registry.db(mod.id)); + // } + // } + // const errors = await registry.errors(); + // if (errors.length) { + // console.error("[notion-enhancer] registry errors:"); + // console.table(errors); + // } + // } +})(); diff --git a/src/electron/client.mjs b/src/electron/client.mjs deleted file mode 100644 index 27ebe2d..0000000 --- a/src/electron/client.mjs +++ /dev/null @@ -1,34 +0,0 @@ -/** - * notion-enhancer - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -(async () => { - const page = location.pathname.split(/[/-]/g).reverse()[0].length === 32, - whitelisted = ['/', '/onboarding'].includes(location.pathname), - signedIn = localStorage['LRU:KeyValueStore2:current-user-id']; - - if (page || (whitelisted && signedIn)) { - const api = await import('./api/index.mjs'), - { fs, registry, web } = api; - - for (const mod of await registry.list((mod) => registry.enabled(mod.id))) { - for (const sheet of mod.css?.client || []) { - web.loadStylesheet(`repo/${mod._dir}/${sheet}`); - } - for (let script of mod.js?.client || []) { - script = await import(fs.localPath(`repo/${mod._dir}/${script}`)); - script.default(api, await registry.db(mod.id)); - } - } - - const errors = await registry.errors(); - if (errors.length) { - console.error('[notion-enhancer] registry errors:'); - console.table(errors); - } - } -})(); diff --git a/src/electron/init.cjs b/src/electron/init.cjs deleted file mode 100644 index 5f60c8e..0000000 --- a/src/electron/init.cjs +++ /dev/null @@ -1,50 +0,0 @@ -/** - * notion-enhancer - * (c) 2022 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -"use strict"; - -module.exports = async (target, __exports, __eval) => { - // if (target === "renderer/preload") { - const { initDatabase } = require("./node.cjs"); - - // require("notion-enhancer/electronApi.cjs"); - // const api = require("notion-enhancer/api/index.cjs"), - // { registry } = api; - - // if (target === "renderer/index") { - // document.addEventListener("readystatechange", (event) => { - // if (document.readyState !== "complete") return false; - // const script = document.createElement("script"); - // script.type = "module"; - // script.src = api.fs.localPath("frame.mjs"); - // document.head.appendChild(script); - // }); - // } - - // if (target === "renderer/preload") { - const db = initDatabase("config"); - // document.addEventListener("readystatechange", (event) => { - // if (document.readyState !== "complete") return false; - // const script = document.createElement("script"); - // script.type = "module"; - // script.src = api.fs.localPath("client.mjs"); - // document.head.appendChild(script); - // }); - // } - - // if (target === "main/main") { - // const { app } = require("electron"); - // app.whenReady().then(require("notion-enhancer/worker.cjs").listen); - // } - - // for (const mod of await registry.list((mod) => registry.enabled(mod.id))) { - // for (const { source, target: scriptTarget } of (mod.js ? mod.js.electron : []) || []) { - // if (`${target}.js` !== scriptTarget) continue; - // const script = require(`notion-enhancer/repo/${mod._dir}/${source}`); - // script(api, await registry.db(mod.id), __exports, __eval); - // } - // } -}; diff --git a/src/electron/init.js b/src/electron/init.js new file mode 100644 index 0000000..93467f8 --- /dev/null +++ b/src/electron/init.js @@ -0,0 +1,36 @@ +/** + * notion-enhancer + * (c) 2022 dragonwocky (https://dragonwocky.me/) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +"use strict"; + +require("./api"); +require("../common/registry.js"); + +module.exports = async (target, __exports, __eval) => { + // clientScripts + if (target === "renderer/preload") { + const { enhancerUrl } = globalThis.__enhancerApi; + document.addEventListener("readystatechange", (event) => { + if (document.readyState !== "complete") return false; + const script = document.createElement("script"); + script.type = "module"; + script.src = enhancerUrl("electron/client.js"); + document.head.appendChild(script); + }); + } + + // electronScripts + const { getMods, getProfile, initDatabase } = globalThis.__enhancerApi; + for (const mod of await getMods()) { + if (!mod.electronScripts || !isEnabled(mod.id)) continue; + for (const { source, target: targetScript } of mod.electronScripts) { + if (`${target}.js` !== targetScript) continue; + const script = require(`notion-enhancer/repo/${mod._dir}/${source}`), + db = await initDatabase([await getProfile(), mod.id]); + script(globalThis.__enhancerApi, db, __exports, __eval); + } + } +}; diff --git a/src/electron/node.cjs b/src/electron/node.cjs deleted file mode 100644 index aba7323..0000000 --- a/src/electron/node.cjs +++ /dev/null @@ -1,67 +0,0 @@ -/** - * notion-enhancer - * (c) 2022 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -"use strict"; - -const os = require("os"), - path = require("path"), - electron = require("electron"), - sqlite = require("better-sqlite3"); - -const notionRequire = (target) => require(`../../../${target}`), - notionPath = (target) => path.resolve(`${__dirname}/../../../${target}`), - notionPlatform = process.platform; - -const enhancerRequire = (target) => require(`../${target}`), - enhancerPath = (target) => path.resolve(`${__dirname}/../${target}`), - enhancerUrl = (target) => `notion://www.notion.so/__notion-enhancer/${target}`, - enhancerVersion = enhancerRequire("package.json").version, - enhancerConfig = path.resolve(`${os.homedir()}/.notion-enhancer.db`); - -const reloadApp = () => { - const args = process.argv.slice(1).filter((arg) => arg !== "--startup"); - electron.app.relaunch({ args }); - electron.app.exit(); -}; - -let __db; -const initDatabase = (table) => { - const db = __db ?? sqlite(enhancerConfig), - init = db.prepare(`CREATE TABLE IF NOT EXISTS ${table} ( - key TEXT PRIMARY KEY, - value TEXT, - mtime INTEGER - )`); - init.run(); - __db = db; - - const insert = db.prepare(`INSERT INTO ${table} (key, value, mtime) VALUES (?, ?, ?)`), - update = db.prepare(`UPDATE ${table} SET value = ?, mtime = ? WHERE key = ?`), - select = db.prepare(`SELECT * FROM ${table} WHERE key = ? LIMIT 1`), - dump = db.prepare(`SELECT * FROM ${table}`); - - return { - get: (key) => select.get(key)?.value, - set: (key, value) => { - if (select.get(key)) return update.run(value, key, Date.now()); - else return insert.run(key, value, Date.now()); - }, - dump: () => dump.all(), - }; -}; - -module.exports = { - notionRequire, - notionPath, - notionPlatform, - enhancerRequire, - enhancerPath, - enhancerUrl, - enhancerVersion, - enhancerConfig, - reloadApp, - initDatabase, -}; diff --git a/src/electron/worker.cjs b/src/electron/worker.cjs deleted file mode 100644 index dbc5e4f..0000000 --- a/src/electron/worker.cjs +++ /dev/null @@ -1,104 +0,0 @@ -/** - * notion-enhancer - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; -module.exports = {}; - -const onMessage = (id, callback) => { - const { ipcMain } = require('electron'); - ipcMain.on(`notion-enhancer:${id}`, callback); -}; - -let enhancerMenu; -module.exports.focusMenu = async () => { - if (enhancerMenu) return enhancerMenu.show(); - - const { fs } = require('notion-enhancer/api/index.cjs'), - { app, session, BrowserWindow } = require('electron'), - windowState = require('electron-window-state')({ - file: 'enhancer-menu-window-state.json', - defaultWidth: 1250, - defaultHeight: 850, - }), - { registry } = require('notion-enhancer/api/index.cjs'), - integratedTitlebar = await registry.enabled('a5658d03-21c6-4088-bade-fa4780459133'); - - enhancerMenu = new BrowserWindow({ - show: true, - frame: !integratedTitlebar, - titleBarStyle: 'hiddenInset', - x: windowState.x, - y: windowState.y, - width: windowState.width, - height: windowState.height, - webPreferences: { - nodeIntegration: true, - enableRemoteModule: true, - session: session.fromPartition('persist:notion'), - preload: require('path').resolve(`${__dirname}/electronApi.cjs`), - }, - }); - enhancerMenu.loadURL(fs.localPath('repo/menu/menu.html')); - windowState.manage(enhancerMenu); - - let appQuit = false; - app.once('before-quit', () => { - appQuit = true; - }); - - // handle opening external links - // must have target="_blank" - enhancerMenu.webContents.on('new-window', (e, url) => { - e.preventDefault(); - require('electron').shell.openExternal(url); - }); - - const trayID = 'f96f4a73-21af-4e3f-a68f-ab4976b020da', - runInBackground = - (await registry.enabled(trayID)) && - (await (await registry.db(trayID)).get(['run_in_background'])); - enhancerMenu.on('close', (e) => { - const isLastWindow = BrowserWindow.getAllWindows().length === 1; - if (!appQuit && isLastWindow && runInBackground) { - enhancerMenu.hide(); - e.preventDefault(); - } else enhancerMenu = null; - }); -}; - -module.exports.getNotionWindows = () => { - const { BrowserWindow } = require('electron'), - windows = BrowserWindow.getAllWindows(); - if (enhancerMenu) return windows.filter((win) => win.id !== enhancerMenu.id); - return windows; -}; - -module.exports.getFocusedNotionWindow = () => { - const { BrowserWindow } = require('electron'), - focusedWindow = BrowserWindow.getFocusedWindow(); - if (enhancerMenu && focusedWindow && focusedWindow.id === enhancerMenu.id) return null; - return focusedWindow; -}; - -module.exports.focusNotion = () => { - const api = require('notion-enhancer/api/index.cjs'), - { createWindow } = api.electron.notionRequire('main/createWindow.js'); - let window = module.exports.getFocusedNotionWindow() || module.exports.getNotionWindows()[0]; - if (!window) window = createWindow('/'); - window.show(); -}; - -module.exports.reload = () => { - const { app } = require('electron'); - app.relaunch({ args: process.argv.slice(1).filter((arg) => arg !== '--startup') }); - app.quit(); -}; - -module.exports.listen = () => { - onMessage('focusMenu', module.exports.focusMenu); - onMessage('focusNotion', module.exports.focusNotion); - onMessage('reload', module.exports.reload); -}; diff --git a/src/vendor/twind.min.js b/src/vendor/twind.min.js index 79f842f..43c8c81 100644 --- a/src/vendor/twind.min.js +++ b/src/vendor/twind.min.js @@ -1,7 +1,7 @@ /** * Skipped minification because the original files appears to be already minified. - * Original file: /npm/@twind/cdn@1.0.1/cdn.global.js + * Original file: /npm/@twind/cdn@1.0.3/cdn.global.js * * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files */ -var twind=function(e){"use strict";let t;function r(){return(r=Object.assign||function(e){for(var t=1;t=0||(n[r]=e[r]);return n}function i(e){return[...e.v,(e.i?"!":"")+e.n].join(":")}let a="undefined"!=typeof CSS&&CSS.escape||(e=>e.replace(/[!"'`*+.,;:\\/<=>?@#$%&^|~()[\]{}]/g,"\\$&").replace(/^\d/,"\\3$& "));function l(e){for(var t=9,r=e.length;r--;)t=Math.imul(t^e.charCodeAt(r),1597334677);return"#"+((t^t>>>9)>>>0).toString(36)}function s(e,t="@media "){return t+c(e).map(e=>("string"==typeof e&&(e={min:e}),e.raw||Object.keys(e).map(t=>`(${t}-width:${e[t]})`).join(" and "))).join(",")}function c(e=[]){return Array.isArray(e)?e:null==e?[]:[e]}function d(e){return e}function f(){}let p={d:0,b:134217728,c:268435456,a:671088640,u:805306368,o:939524096};function u(e){var t;return(null==(t=e.match(/[-=:;]/g))?void 0:t.length)||0}function g(e){return Math.min(/(?:^|width[^\d]+)(\d+(?:.\d+)?)(p)?/.test(e)?+RegExp.$1/(RegExp.$2?15:1)/10:0,15)<<22|Math.min(u(e),15)<<18}let m=["rst-c","st-ch","h-chi","y-lin","nk","sited","ecked","pty","ad-on","cus-w","ver","cus","cus-v","tive","sable","tiona","quire"];function b({n:e,i:t,v:r=[]},o,n,a){for(let l of(e&&(e=i({n:e,i:t,v:r})),a=[...c(a)],r)){let d=o.theme("screens",l);for(let f of c(d&&s(d)||o.v(l))){var p;a.push(f),n|=d?67108864|g(f):"dark"==l?1073741824:"@"==f[0]?g(f):(p=f,1<<~(/:([a-z-]+)/.test(p)&&~m.indexOf(RegExp.$1.slice(2,7))||-18))}}return{n:e,p:n,r:a,i:t}}let h=new Map;function x(e){if(e.d){let t=[],r=w(e.r.reduce((e,r)=>"@"==r[0]?(t.push(r),e):r?w(e,e=>w(r,t=>{let r=/(:merge\(.+?\))(:[a-z-]+|\\[.+])/.exec(t);if(r){let o=e.indexOf(r[1]);return~o?e.slice(0,o)+r[0]+e.slice(o+r[1].length):y(e,t)}return y(t,e)})):e,"&"),t=>y(t,e.n?"."+a(e.n):""));return r&&t.push(r.replace(/:merge\((.+?)\)/g,"$1")),t.reduceRight((e,t)=>t+"{"+e+"}",e.d)}}function w(e,t){return e.replace(/ *((?:\(.+?\)|\[.+?\]|[^,])+) *(,|$)/g,(e,r,o)=>t(r)+o)}function y(e,t){return e.replace(/&/g,t)}let v=new Intl.Collator("en",{numeric:!0});function k(e,t){for(var r=0,o=e.length;r>1;0>=$(e[n],t)?r=n+1:o=n}return o}function $(e,t){let r=e.p&p.o;return r==(t.p&p.o)&&(r==p.b||r==p.o)?0:e.p-t.p||e.o-t.o||v.compare(e.n,t.n)}function S(e,t){return Math.round(parseInt(e,16)*t)}function C(e,t={}){if("function"==typeof e)return e(t);let{opacityValue:r="1",opacityVariable:o}=t,n=o?`var(${o})`:r;if(e.includes(""))return e.replace("",n);if("#"==e[0]&&(4==e.length||7==e.length)){let i=(e.length-1)/3,a=[17,1,.062272][i-1];return`rgba(${[S(e.substr(1,i),a),S(e.substr(1+i,i),a),S(e.substr(1+2*i,i),a),n]})`}return"1"==n?e:"0"==n?"#0000":e.replace(/^(rgb|hsl)(\([^)]+)\)$/,`$1a$2,${n})`)}function A(e,t,r,o,n=[]){return function e(t,{n:r,p:o,r:n=[],i:i},a){let d=[],f="",m=0,b=0;for(let h in t||{}){var w,y;let v=t[h];if("@"==h[0]){if(!v)continue;if("a"==h[1]){d.push(...T(r,o,D(""+v),a,o,n,i,!0));continue}if("l"==h[1]){for(let k of c(v))d.push(...e(k,{n:r,p:(w=p[h[7]],o&~p.o|w),r:n,i:i},a));continue}if("i"==h[1]){d.push(...c(v).map(e=>({p:-1,o:0,r:[],d:h+" "+e})));continue}if("k"==h[1]){d.push({p:p.d,o:0,r:[h],d:e(v,{p:p.d},a).map(x).join("")});continue}if("f"==h[1]){d.push(...c(v).map(t=>({p:p.d,o:0,r:[h],d:e(t,{p:p.d},a).map(x).join("")})));continue}}if("object"!=typeof v||Array.isArray(v))"label"==h&&v?r=v+l(JSON.stringify([o,i,t])):(v||0===v)&&(h=h.replace(/[A-Z]/g,e=>"-"+e.toLowerCase()),b+=1,m=Math.max(m,"-"==(y=h)[0]?0:u(y)+(/^(?:(border-(?!w|c|sty)|[tlbr].{2,4}m?$|c.{7}$)|([fl].{5}l|g.{8}$|pl))/.test(y)?+!!RegExp.$1||-!!RegExp.$2:0)+1),f+=(f?";":"")+c(v).map(e=>a.s(h,z(""+e,a.theme)+(i?" !important":""))).join(";"));else if("@"==h[0]||h.includes("&")){let S=o;"@"==h[0]&&(h=h.replace(/\bscreen\(([^)]+)\)/g,(e,t)=>{let r=a.theme("screens",t);return r?(S|=67108864,s(r,"")):e}),S|=g(h)),d.push(...e(v,{n:r,p:S,r:[...n,h],i:i},a))}else d.push(...e(v,{p:o,r:[...n,h]},a))}return d.unshift({n:r,p:o,o:Math.max(0,15-b)+1.5*Math.min(m||15,15),r:n,d:f}),d.sort($)}(e,b(t,r,o,n),r)}function z(e,t){return e.replace(/theme\((["'`])?(.+?)\1(?:\s*,\s*(["'`])?(.+?)\3)?\)/g,(e,r,o,n,i)=>{let a=t(o,i);return"function"==typeof a&&/color|fill|stroke/i.test(o)?C(a):""+a})}function O(e,t){let r;let n=[];for(let i of e)i.d&&i.n?(null==r?void 0:r.p)==i.p&&""+r.r==""+i.r?(r.c=[r.c,i.c].filter(Boolean).join(" "),r.d=r.d+";"+i.d):n.push(r=o({},i,{n:i.n&&t})):n.push(o({},i,{n:i.n&&t}));return n}function j(e,t,r=p.u,n,a){let l=[];for(let s of e)for(let d of function(e,t,r,n,a){var l;e=o({},e,{i:e.i||a});let s=function(e,t){let r=h.get(e.n);return r?r(e,t):t.r(e.n,"dark"==e.v[0])}(e,t);return s?"string"==typeof s?({r:n,p:r}=b(e,t,r,n),O(j(D(s),t,r,n,e.i),e.n)):Array.isArray(s)?s.map(e=>{var t,i;return o({o:0},e,{r:[...c(n),...c(e.r)],p:(t=r,i=null!=(l=e.p)?l:r,t&~p.o|i)})}):A(s,e,t,r,n):[{c:i(e),p:0,o:0,r:[]}]}(s,t,r,n,a))l.splice(k(l,d),0,d);return l}function T(e,t,r,n,i,a,l,s){return O((s?r.flatMap(e=>j([e],n,i,a,l)):j(r,n,i,a,l)).map(e=>e.p&p.o&&(e.n||t==p.b)?o({},e,{p:e.p&~p.o|t,o:0}):e),e)}function F(e,t){if("("!=e[e.length-1]){let r=[],o=!1,n=!1,i="";for(let a of e)if(!("("==a||/[~@]$/.test(a))){if("!"==a[0]&&(a=a.slice(1),o=!o),a.endsWith(":")){r["dark:"==a?"unshift":"push"](a.slice(0,-1));continue}"-"==a[0]&&(a=a.slice(1),n=!n),a.endsWith("-")&&(a=a.slice(0,-1)),a&&"&"!=a&&(i+=(i&&"-")+a)}i&&(n&&(i="-"+i),t[0].push({n:i,v:r.filter(E),i:o}))}}function E(e,t,r){return r.indexOf(e)==t}let R=new Map;function D(e){let t=R.get(e);if(!t){let r=[],o=[[]],n=0,a=0,s=null,c=0,d=(t,i=0)=>{n!=c&&(r.push(e.slice(n,c+i)),t&&F(r,o)),n=c+1};for(;c{let{n:i,p:a,r:l,i:s}=b(e,n,t);return r&&T(i,t,r,n,a,l,s,o)},h.set(e,n),e}(g.length>1?g.slice(0,-1)+l(JSON.stringify([g,m])):g+"("+function(e,t=","){return e.map(i).join(t)}(m)+")",p.a,m,/@$/.test(g))],o)}u=r.lastIndexOf("(",u-1)}r.length=u+1}else/[~@]/.test(f)&&"("==e[c+1]&&o.unshift([])}d(!0),R.set(e,t=o[0])}return t}function W(e){var{presets:t=[]}=e,r=n(e,["presets"]);let i={preflight:!1!==r.preflight&&[],darkMode:void 0,darkColor:void 0,theme:{},variants:c(r.variants),rules:c(r.rules),ignorelist:c(r.ignorelist),hash:r.hash,stringify:r.stringify||M};for(let a of c([...t,{darkMode:r.darkMode,darkColor:r.darkColor,preflight:!1!==r.preflight&&c(r.preflight),theme:r.theme,hash:r.hash,stringify:r.stringify}])){let{preflight:l,darkMode:s=i.darkMode,darkColor:d=i.darkColor,theme:f,variants:p,rules:u,ignorelist:g,hash:m=i.hash,stringify:b=i.stringify}="function"==typeof a?a(i):a;i={preflight:!1!==i.preflight&&!1!==l&&[...i.preflight,...c(l)],darkMode:s,darkColor:d,theme:o({},i.theme,f,{extend:o({},i.theme.extend,null==f?void 0:f.extend)}),variants:[...i.variants,...c(p)],rules:[...i.rules,...c(u)],ignorelist:[...i.ignorelist,...c(g)],hash:m,stringify:b}}return i}function M(e,t){return e+":"+t}function L(e,t,r){return[e,V(t,r)]}function V(e,t){return"function"==typeof e?e:"string"==typeof e&&/^[\w-]+$/.test(e)?(r,o)=>({[e]:t?t(r,o):U(r,1)}):t=>e||{[t[1]]:U(t,2)}}function U(e,t,r=e.slice(t).find(Boolean)||e.$$||e.input){return"-"==e.input[0]?`calc(${r} * -1)`:r}function I(e,t,r,o){return[e,function(e,t,r){let o="string"==typeof t?(e,o)=>({[t]:r?r(e,o):e._}):t||(({1:e,_:t},r,o)=>({[e||o]:t}));return(t,r)=>{var n;let i=P(e||t[1]),a=null!=(n=r.theme(i,t.$$))?n:_(t.$$,i,r);if(null!=a)return t._=U(t,0,a),o(t,r,i)}}(t,r,o)]}function N(e,t={},r){return[e,function(e={},t){return(r,o)=>{let{section:n=P(r[0]).replace("-","")+"Color"}=e;if(!/^(\[[^\]]+]|[^/]+?)(?:\/(.+))?$/.test(r.$$))return;let{$1:i,$2:a}=RegExp,l=o.theme(n,i)||_(i,n,o);if(!l||"object"==typeof l)return;let{opacityVariable:s=`--tw-${r[0].replace(/-$/,"")}-opacity`,opacitySection:c=n.replace("Color","Opacity"),property:d=n,selector:f}=e,p=o.theme(c,a||"DEFAULT")||a&&_(a,c,o),u=t||(({_:e})=>{let t=B(d,e);return f?{[f]:t}:t});r._={value:C(l,{opacityVariable:s||void 0,opacityValue:p||void 0}),color:e=>C(l,e),opacityVariable:s||void 0,opacityValue:p||void 0};let g=u(r,o);if(!r.dark){let m=o.d(n,i,l);m&&m!==l&&(r._={value:C(m,{opacityVariable:s||void 0,opacityValue:p||"1"}),color:e=>C(m,e),opacityVariable:s||void 0,opacityValue:p||void 0},g={"&":g,[o.v("dark")]:u(r,o)})}return g}}(t,r)]}function B(e,t){let r={};return"string"==typeof t?r[e]=t:(t.opacityVariable&&t.value.includes(t.opacityVariable)&&(r[t.opacityVariable]=t.opacityValue||"1"),r[e]=t.value),r}function _(e,t,r){if("["==e[0]&&"]"==e.slice(-1)&&(e=H(z(e.slice(1,-1),r.theme)),!(/color|fill|stroke/i.test(t)&&!(/^color:/.test(e)||/^(#|((hsl|rgb)a?|hwb|lab|lch|color)\(|[a-z]+$)/.test(e))||/image/i.test(t)&&!(/^image:/.test(e)||/^[a-z-]+\(/.test(e))||/weight/i.test(t)&&!(/^(number|any):/.test(e)||/^\d+$/.test(e))||/position/i.test(t)&&/^(length|size):/.test(e))))return e.replace(/^[a-z-]+:/,"")}function P(e){return e.replace(/-./g,e=>e[1].toUpperCase())}function H(e){return e.includes("url(")?e.replace(/(.*?)(url\(.*?\))(.*?)/g,(e,t="",r,o="")=>H(t)+r+H(o)):e.replace(/(^|[^\\])_+/g,(e,t)=>t+" ".repeat(e.length-t.length)).replace(/\\_/g,"_").replace(/(calc|min|max|clamp)\(.+\)/g,e=>e.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g,"$1 $2 "))}function q(e,t,r,o,n,i){for(let a of t){let l=r.get(a);l||r.set(a,l=o(a));let s=l(e,n,i);if(s)return s}}function G(e){var t;return J(e[0],"function"==typeof(t=e[1])?t:()=>t)}function Y(e){var t,r;return Array.isArray(e)?J(e[0],V(e[1],e[2])):J(e,V(t,r))}function J(e,t){return X(e,(e,r,o,n)=>{let i=r.exec(e);if(i)return i.$$=e.slice(i[0].length),i.dark=n,t(i,o)})}function X(e,t){let r=c(e).map(Z);return(e,o,n)=>{for(let i of r){let a=t(e,i,o,n);if(a)return a}}}function Z(e){return"string"==typeof e?RegExp("^"+e+(e.includes("$")||"-"==e.slice(-1)?"":"$")):e}function K(e,t){return e.replace(/--(tw(?:-[\w-]+)?)\b/g,(e,r)=>"--"+t(r).replace("#",""))}function Q(e){let t=document.querySelector(e||"style[data-twind]");return t&&"STYLE"==t.tagName||((t=document.createElement("style")).dataset.twind="",document.head.prepend(t)),t}function ee(e,t){let r=e?function(e){let t=e&&"string"!=typeof e?e:Q(e);return{target:t,snapshot(){let e=Array.from(t.childNodes,e=>e.textContent);return()=>{this.clear(),e.forEach(this.insert)}},clear(){t.textContent=""},destroy(){t.remove()},insert(e,r){t.insertBefore(document.createTextNode(e),t.childNodes[r]||null)},resume:f}}():function(e){let t=(null==e?void 0:e.cssRules)?e:(e&&"string"!=typeof e?e:Q(e)).sheet;return{target:t,snapshot(){let e=Array.from(t.cssRules,e=>e.cssText);return()=>{this.clear(),e.forEach(this.insert)}},clear(){for(let e=t.cssRules.length;e--;)t.deleteRule(e)},destroy(){var e;null==(e=t.ownerNode)||e.remove()},insert(e,r){try{t.insertRule(e,r)}catch(o){t.insertRule(":root{}",r),/:-[mwo]/.test(e)}},resume:f}}();return t||(r.resume=et),r}function et(e,t){var r,o;let n=((r=this.target).ownerNode||r).textContent||(r.cssRules?Array.from(r.cssRules,e=>e.cssText):c(r)).join(""),i=/\/\*!([\da-z]+),([\da-z]+)(?:,(.+?))?\*\//g;if(i.test(n)){let a;for(let l of(i.lastIndex=0,this.clear(),document.querySelectorAll("[class]")))e(l.getAttribute("class"));for(;o=i.exec(n),a&&t(n.slice(a.index+a[0].length,null==o?void 0:o.index),{p:parseInt(a[1],36),o:parseInt(a[2],36)/2,n:a[3]}),a=o;);}}let er=new Proxy(f,{apply:(e,r,o)=>t(o[0]),get(e,r){let o=t[r];return"function"==typeof o?function(){return o.apply(t,arguments)}:o}});var eo=new Map([["align-self","-ms-grid-row-align"],["color-adjust","-webkit-print-color-adjust"],["column-gap","grid-column-gap"],["forced-color-adjust","-ms-high-contrast-adjust"],["gap","grid-gap"],["grid-template-columns","-ms-grid-columns"],["grid-template-rows","-ms-grid-rows"],["justify-self","-ms-grid-column-align"],["margin-inline-end","-webkit-margin-end"],["margin-inline-start","-webkit-margin-start"],["mask-border","-webkit-mask-box-image"],["mask-border-outset","-webkit-mask-box-image-outset"],["mask-border-slice","-webkit-mask-box-image-slice"],["mask-border-source","-webkit-mask-box-image-source"],["mask-border-repeat","-webkit-mask-box-image-repeat"],["mask-border-width","-webkit-mask-box-image-width"],["overflow-wrap","word-wrap"],["padding-inline-end","-webkit-padding-end"],["padding-inline-start","-webkit-padding-start"],["print-color-adjust","color-adjust"],["row-gap","grid-row-gap"],["scroll-margin-bottom","scroll-snap-margin-bottom"],["scroll-margin-left","scroll-snap-margin-left"],["scroll-margin-right","scroll-snap-margin-right"],["scroll-margin-top","scroll-snap-margin-top"],["scroll-margin","scroll-snap-margin"],["text-combine-upright","-ms-text-combine-horizontal"]]);let en=[["-webkit-",1],["-moz-",2],["-ms-",4]],ei={__proto__:null,inherit:"inherit",current:"currentColor",transparent:"transparent",black:"#000",white:"#fff",slate:{50:"#f8fafc",100:"#f1f5f9",200:"#e2e8f0",300:"#cbd5e1",400:"#94a3b8",500:"#64748b",600:"#475569",700:"#334155",800:"#1e293b",900:"#0f172a"},gray:{50:"#f9fafb",100:"#f3f4f6",200:"#e5e7eb",300:"#d1d5db",400:"#9ca3af",500:"#6b7280",600:"#4b5563",700:"#374151",800:"#1f2937",900:"#111827"},zinc:{50:"#fafafa",100:"#f4f4f5",200:"#e4e4e7",300:"#d4d4d8",400:"#a1a1aa",500:"#71717a",600:"#52525b",700:"#3f3f46",800:"#27272a",900:"#18181b"},neutral:{50:"#fafafa",100:"#f5f5f5",200:"#e5e5e5",300:"#d4d4d4",400:"#a3a3a3",500:"#737373",600:"#525252",700:"#404040",800:"#262626",900:"#171717"},stone:{50:"#fafaf9",100:"#f5f5f4",200:"#e7e5e4",300:"#d6d3d1",400:"#a8a29e",500:"#78716c",600:"#57534e",700:"#44403c",800:"#292524",900:"#1c1917"},red:{50:"#fef2f2",100:"#fee2e2",200:"#fecaca",300:"#fca5a5",400:"#f87171",500:"#ef4444",600:"#dc2626",700:"#b91c1c",800:"#991b1b",900:"#7f1d1d"},orange:{50:"#fff7ed",100:"#ffedd5",200:"#fed7aa",300:"#fdba74",400:"#fb923c",500:"#f97316",600:"#ea580c",700:"#c2410c",800:"#9a3412",900:"#7c2d12"},amber:{50:"#fffbeb",100:"#fef3c7",200:"#fde68a",300:"#fcd34d",400:"#fbbf24",500:"#f59e0b",600:"#d97706",700:"#b45309",800:"#92400e",900:"#78350f"},yellow:{50:"#fefce8",100:"#fef9c3",200:"#fef08a",300:"#fde047",400:"#facc15",500:"#eab308",600:"#ca8a04",700:"#a16207",800:"#854d0e",900:"#713f12"},lime:{50:"#f7fee7",100:"#ecfccb",200:"#d9f99d",300:"#bef264",400:"#a3e635",500:"#84cc16",600:"#65a30d",700:"#4d7c0f",800:"#3f6212",900:"#365314"},green:{50:"#f0fdf4",100:"#dcfce7",200:"#bbf7d0",300:"#86efac",400:"#4ade80",500:"#22c55e",600:"#16a34a",700:"#15803d",800:"#166534",900:"#14532d"},emerald:{50:"#ecfdf5",100:"#d1fae5",200:"#a7f3d0",300:"#6ee7b7",400:"#34d399",500:"#10b981",600:"#059669",700:"#047857",800:"#065f46",900:"#064e3b"},teal:{50:"#f0fdfa",100:"#ccfbf1",200:"#99f6e4",300:"#5eead4",400:"#2dd4bf",500:"#14b8a6",600:"#0d9488",700:"#0f766e",800:"#115e59",900:"#134e4a"},cyan:{50:"#ecfeff",100:"#cffafe",200:"#a5f3fc",300:"#67e8f9",400:"#22d3ee",500:"#06b6d4",600:"#0891b2",700:"#0e7490",800:"#155e75",900:"#164e63"},sky:{50:"#f0f9ff",100:"#e0f2fe",200:"#bae6fd",300:"#7dd3fc",400:"#38bdf8",500:"#0ea5e9",600:"#0284c7",700:"#0369a1",800:"#075985",900:"#0c4a6e"},blue:{50:"#eff6ff",100:"#dbeafe",200:"#bfdbfe",300:"#93c5fd",400:"#60a5fa",500:"#3b82f6",600:"#2563eb",700:"#1d4ed8",800:"#1e40af",900:"#1e3a8a"},indigo:{50:"#eef2ff",100:"#e0e7ff",200:"#c7d2fe",300:"#a5b4fc",400:"#818cf8",500:"#6366f1",600:"#4f46e5",700:"#4338ca",800:"#3730a3",900:"#312e81"},violet:{50:"#f5f3ff",100:"#ede9fe",200:"#ddd6fe",300:"#c4b5fd",400:"#a78bfa",500:"#8b5cf6",600:"#7c3aed",700:"#6d28d9",800:"#5b21b6",900:"#4c1d95"},purple:{50:"#faf5ff",100:"#f3e8ff",200:"#e9d5ff",300:"#d8b4fe",400:"#c084fc",500:"#a855f7",600:"#9333ea",700:"#7e22ce",800:"#6b21a8",900:"#581c87"},fuchsia:{50:"#fdf4ff",100:"#fae8ff",200:"#f5d0fe",300:"#f0abfc",400:"#e879f9",500:"#d946ef",600:"#c026d3",700:"#a21caf",800:"#86198f",900:"#701a75"},pink:{50:"#fdf2f8",100:"#fce7f3",200:"#fbcfe8",300:"#f9a8d4",400:"#f472b6",500:"#ec4899",600:"#db2777",700:"#be185d",800:"#9d174d",900:"#831843"},rose:{50:"#fff1f2",100:"#ffe4e6",200:"#fecdd3",300:"#fda4af",400:"#fb7185",500:"#f43f5e",600:"#e11d48",700:"#be123c",800:"#9f1239",900:"#881337"}},ea={screens:{sm:"640px",md:"768px",lg:"1024px",xl:"1280px","2xl":"1536px"},colors:ei,columns:{auto:"auto","3xs":"16rem","2xs":"18rem",xs:"20rem",sm:"24rem",md:"28rem",lg:"32rem",xl:"36rem","2xl":"42rem","3xl":"48rem","4xl":"56rem","5xl":"64rem","6xl":"72rem","7xl":"80rem"},spacing:o({px:"1px",0:"0px"},ec(4,"rem",4,.5,.5),ec(12,"rem",4,5),{14:"3.5rem"},ec(64,"rem",4,16,4),{72:"18rem",80:"20rem",96:"24rem"}),durations:{75:"75ms",100:"100ms",150:"150ms",200:"200ms",300:"300ms",500:"500ms",700:"700ms",1e3:"1000ms"},animation:{none:"none",spin:"spin 1s linear infinite",ping:"ping 1s cubic-bezier(0,0,0.2,1) infinite",pulse:"pulse 2s cubic-bezier(0.4,0,0.6,1) infinite",bounce:"bounce 1s infinite"},aspectRatio:{auto:"auto",square:"1/1",video:"16/9"},backdropBlur:ed("blur"),backdropBrightness:ed("brightness"),backdropContrast:ed("contrast"),backdropGrayscale:ed("grayscale"),backdropHueRotate:ed("hueRotate"),backdropInvert:ed("invert"),backdropOpacity:ed("opacity"),backdropSaturate:ed("saturate"),backdropSepia:ed("sepia"),backgroundColor:ed("colors"),backgroundImage:{none:"none"},backgroundOpacity:ed("opacity"),backgroundSize:{auto:"auto",cover:"cover",contain:"contain"},blur:{none:"none",0:"0",sm:"4px",DEFAULT:"8px",md:"12px",lg:"16px",xl:"24px","2xl":"40px","3xl":"64px"},brightness:o({},ec(200,"",100,0,50),ec(110,"",100,90,5),{75:"0.75",125:"1.25"}),borderColor:({theme:e})=>o({DEFAULT:e("colors.gray.200","currentColor")},e("colors")),borderOpacity:ed("opacity"),borderRadius:{none:"0px",sm:"0.125rem",DEFAULT:"0.25rem",md:"0.375rem",lg:"0.5rem",xl:"0.75rem","2xl":"1rem","3xl":"1.5rem","1/2":"50%",full:"9999px"},borderSpacing:ed("spacing"),borderWidth:o({DEFAULT:"1px"},es(8,"px")),boxShadow:{sm:"0 1px 2px 0 rgba(0,0,0,0.05)",DEFAULT:"0 1px 3px 0 rgba(0,0,0,0.1), 0 1px 2px -1px rgba(0,0,0,0.1)",md:"0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1)",lg:"0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)",xl:"0 20px 25px -5px rgba(0,0,0,0.1), 0 8px 10px -6px rgba(0,0,0,0.1)","2xl":"0 25px 50px -12px rgba(0,0,0,0.25)",inner:"inset 0 2px 4px 0 rgba(0,0,0,0.05)",none:"0 0 #0000"},boxShadowColor:ed("colors"),caretColor:ed("colors"),accentColor:({theme:e})=>o({auto:"auto"},e("colors")),contrast:o({},ec(200,"",100,0,50),{75:"0.75",125:"1.25"}),content:{none:"none"},divideColor:ed("borderColor"),divideOpacity:ed("borderOpacity"),divideWidth:ed("borderWidth"),dropShadow:{sm:"0 1px 1px rgba(0,0,0,0.05)",DEFAULT:["0 1px 2px rgba(0,0,0,0.1)","0 1px 1px rgba(0,0,0,0.06)"],md:["0 4px 3px rgba(0,0,0,0.07)","0 2px 2px rgba(0,0,0,0.06)"],lg:["0 10px 8px rgba(0,0,0,0.04)","0 4px 3px rgba(0,0,0,0.1)"],xl:["0 20px 13px rgba(0,0,0,0.03)","0 8px 5px rgba(0,0,0,0.08)"],"2xl":"0 25px 25px rgba(0,0,0,0.15)",none:"0 0 #0000"},fill:ed("colors"),grayscale:{DEFAULT:"100%",0:"0"},hueRotate:{0:"0deg",15:"15deg",30:"30deg",60:"60deg",90:"90deg",180:"180deg"},invert:{DEFAULT:"100%",0:"0"},flex:{1:"1 1 0%",auto:"1 1 auto",initial:"0 1 auto",none:"none"},flexBasis:({theme:e})=>o({},e("spacing"),el(2,6),el(12,12),{auto:"auto",full:"100%"}),flexGrow:{DEFAULT:1,0:0},flexShrink:{DEFAULT:1,0:0},fontFamily:{sans:'ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"'.split(","),serif:'ui-serif,Georgia,Cambria,"Times New Roman",Times,serif'.split(","),mono:'ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace'.split(",")},fontSize:{xs:["0.75rem","1rem"],sm:["0.875rem","1.25rem"],base:["1rem","1.5rem"],lg:["1.125rem","1.75rem"],xl:["1.25rem","1.75rem"],"2xl":["1.5rem","2rem"],"3xl":["1.875rem","2.25rem"],"4xl":["2.25rem","2.5rem"],"5xl":["3rem","1"],"6xl":["3.75rem","1"],"7xl":["4.5rem","1"],"8xl":["6rem","1"],"9xl":["8rem","1"]},fontWeight:{thin:"100",extralight:"200",light:"300",normal:"400",medium:"500",semibold:"600",bold:"700",extrabold:"800",black:"900"},gap:ed("spacing"),gradientColorStops:ed("colors"),gridAutoColumns:{auto:"auto",min:"min-content",max:"max-content",fr:"minmax(0,1fr)"},gridAutoRows:{auto:"auto",min:"min-content",max:"max-content",fr:"minmax(0,1fr)"},gridColumn:{auto:"auto","span-full":"1 / -1"},gridRow:{auto:"auto","span-full":"1 / -1"},gridTemplateColumns:{none:"none"},gridTemplateRows:{none:"none"},height:({theme:e})=>o({},e("spacing"),el(2,6),{min:"min-content",max:"max-content",fit:"fit-content",auto:"auto",full:"100%",screen:"100vh"}),inset:({theme:e})=>o({},e("spacing"),el(2,4),{auto:"auto",full:"100%"}),keyframes:{spin:{from:{transform:"rotate(0deg)"},to:{transform:"rotate(360deg)"}},ping:{"0%":{transform:"scale(1)",opacity:"1"},"75%,100%":{transform:"scale(2)",opacity:"0"}},pulse:{"0%,100%":{opacity:"1"},"50%":{opacity:".5"}},bounce:{"0%, 100%":{transform:"translateY(-25%)",animationTimingFunction:"cubic-bezier(0.8,0,1,1)"},"50%":{transform:"none",animationTimingFunction:"cubic-bezier(0,0,0.2,1)"}}},letterSpacing:{tighter:"-0.05em",tight:"-0.025em",normal:"0em",wide:"0.025em",wider:"0.05em",widest:"0.1em"},lineHeight:o({},ec(10,"rem",4,3),{none:"1",tight:"1.25",snug:"1.375",normal:"1.5",relaxed:"1.625",loose:"2"}),margin:({theme:e})=>o({auto:"auto"},e("spacing")),maxHeight:({theme:e})=>o({full:"100%",min:"min-content",max:"max-content",fit:"fit-content",screen:"100vh"},e("spacing")),maxWidth:({theme:e,breakpoints:t})=>o({},t(e("screens")),{none:"none",0:"0rem",xs:"20rem",sm:"24rem",md:"28rem",lg:"32rem",xl:"36rem","2xl":"42rem","3xl":"48rem","4xl":"56rem","5xl":"64rem","6xl":"72rem","7xl":"80rem",full:"100%",min:"min-content",max:"max-content",fit:"fit-content",prose:"65ch"}),minHeight:{0:"0px",full:"100%",min:"min-content",max:"max-content",fit:"fit-content",screen:"100vh"},minWidth:{0:"0px",full:"100%",min:"min-content",max:"max-content",fit:"fit-content"},opacity:o({},ec(100,"",100,0,10),{5:"0.05",25:"0.25",75:"0.75",95:"0.95"}),order:{first:"-9999",last:"9999",none:"0"},padding:ed("spacing"),placeholderColor:ed("colors"),placeholderOpacity:ed("opacity"),outlineColor:ed("colors"),outlineOffset:es(8,"px"),outlineWidth:es(8,"px"),ringColor:({theme:e})=>o({},e("colors"),{DEFAULT:e("colors.blue.500","#3b82f6")}),ringOffsetColor:ed("colors"),ringOffsetWidth:es(8,"px"),ringOpacity:({theme:e})=>o({},e("opacity"),{DEFAULT:"0.5"}),ringWidth:o({DEFAULT:"3px"},es(8,"px")),rotate:o({},es(2,"deg"),es(12,"deg",3),es(180,"deg",45)),saturate:ec(200,"",100,0,50),scale:o({},ec(150,"",100,0,50),ec(110,"",100,90,5),{75:"0.75",125:"1.25"}),scrollMargin:ed("spacing"),scrollPadding:ed("spacing"),sepia:{0:"0",DEFAULT:"100%"},skew:o({},es(2,"deg"),es(12,"deg",3)),space:ed("spacing"),stroke:ed("colors"),strokeWidth:ec(2),textColor:ed("colors"),textDecorationColor:ed("colors"),textDecorationThickness:o({"from-font":"from-font",auto:"auto"},es(8,"px")),textUnderlineOffset:o({auto:"auto"},es(8,"px")),textIndent:ed("spacing"),textOpacity:ed("opacity"),transitionDuration:({theme:e})=>o({},e("durations"),{DEFAULT:"150ms"}),transitionDelay:ed("durations"),transitionProperty:{none:"none",all:"all",DEFAULT:"color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter",colors:"color,background-color,border-color,text-decoration-color,fill,stroke",opacity:"opacity",shadow:"box-shadow",transform:"transform"},transitionTimingFunction:{DEFAULT:"cubic-bezier(0.4,0,0.2,1)",linear:"linear",in:"cubic-bezier(0.4,0,1,1)",out:"cubic-bezier(0,0,0.2,1)","in-out":"cubic-bezier(0.4,0,0.2,1)"},translate:({theme:e})=>o({},e("spacing"),el(2,4),{full:"100%"}),width:({theme:e})=>o({min:"min-content",max:"max-content",fit:"fit-content",screen:"100vw"},e("flexBasis")),willChange:{scroll:"scroll-position"},zIndex:o({},ec(50,"",1,0,10),{auto:"auto"})};function el(e,t){let r={};do for(var o=1;ot(e)}let ef={"*,::before,::after":{boxSizing:"border-box",borderWidth:"0",borderStyle:"solid",borderColor:"theme(borderColor.DEFAULT, currentColor)"},"::before,::after":{"--tw-content":"''"},html:{lineHeight:1.5,WebkitTextSizeAdjust:"100%",MozTabSize:"4",tabSize:4,fontFamily:`theme(fontFamily.sans, ${ea.fontFamily.sans})`},body:{margin:"0",lineHeight:"inherit"},hr:{height:"0",color:"inherit",borderTopWidth:"1px"},"abbr:where([title])":{textDecoration:"underline dotted"},"h1,h2,h3,h4,h5,h6":{fontSize:"inherit",fontWeight:"inherit"},a:{color:"inherit",textDecoration:"inherit"},"b,strong":{fontWeight:"bolder"},"code,kbd,samp,pre":{fontFamily:`theme(fontFamily.mono, ${ea.fontFamily.mono})`,fontSize:"1em"},small:{fontSize:"80%"},"sub,sup":{fontSize:"75%",lineHeight:0,position:"relative",verticalAlign:"baseline"},sub:{bottom:"-0.25em"},sup:{top:"-0.5em"},table:{textIndent:"0",borderColor:"inherit",borderCollapse:"collapse"},"button,input,optgroup,select,textarea":{fontFamily:"inherit",fontSize:"100%",lineHeight:"inherit",color:"inherit",margin:"0",padding:"0"},"button,select":{textTransform:"none"},"button,[type='button'],[type='reset'],[type='submit']":{WebkitAppearance:"button",backgroundColor:"transparent",backgroundImage:"none"},":-moz-focusring":{outline:"auto"},":-moz-ui-invalid":{boxShadow:"none"},progress:{verticalAlign:"baseline"},"::-webkit-inner-spin-button,::-webkit-outer-spin-button":{height:"auto"},"[type='search']":{WebkitAppearance:"textfield",outlineOffset:"-2px"},"::-webkit-search-decoration":{WebkitAppearance:"none"},"::-webkit-file-upload-button":{WebkitAppearance:"button",font:"inherit"},summary:{display:"list-item"},"blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre":{margin:"0"},fieldset:{margin:"0",padding:"0"},legend:{padding:"0"},"ol,ul,menu":{listStyle:"none",margin:"0",padding:"0"},textarea:{resize:"vertical"},"input::placeholder,textarea::placeholder":{opacity:1,color:"theme(colors.gray.400, #9ca3af)"},'button,[role="button"]':{cursor:"pointer"},":disabled":{cursor:"default"},"img,svg,video,canvas,audio,iframe,embed,object":{display:"block",verticalAlign:"middle"},"img,video":{maxWidth:"100%",height:"auto"},"[hidden]":{display:"none"}},ep=[L("\\[([-\\w]+):(.+)]",({1:e,2:t},r)=>({"@layer overrides":{"&":{[e]:_(`[${t}]`,e,r)}}})),L("(group|peer)(~[^-[]+)?",({input:e},{h:t})=>[{c:t(e)}]),I("aspect-","aspectRatio"),L("container",(e,{theme:t})=>{let{screens:r=t("screens"),center:n,padding:i}=t("container"),a=o({width:"100%",marginRight:n&&"auto",marginLeft:n&&"auto"},d("xs"));for(let l in r){let c=r[l];"string"==typeof c&&(a[s(c)]={"&":o({maxWidth:c},d(l))})}return a;function d(e){let t=i&&("string"==typeof i?i:i[e]||i.DEFAULT);if(t)return{paddingRight:t,paddingLeft:t}}}),I("content-","content",({_:e})=>({"--tw-content":e,content:"var(--tw-content)"})),L("(?:box-)?decoration-(slice|clone)","boxDecorationBreak"),L("box-(border|content)","boxSizing",({1:e})=>e+"-box"),L("hidden",{display:"none"}),L("table-(auto|fixed)","tableLayout"),L(["(block|flex|table|grid|inline|contents|flow-root|list-item)","(inline-(block|flex|table|grid))","(table-(caption|cell|column|row|(column|row|footer|header)-group))"],"display"),"(float)-(left|right|none)","(clear)-(left|right|none|both)","(overflow(?:-[xy])?)-(auto|hidden|clip|visible|scroll)","(isolation)-(auto)",L("isolate","isolation"),L("object-(contain|cover|fill|none|scale-down)","objectFit"),I("object-","objectPosition"),L("object-(top|bottom|center|(left|right)(-(top|bottom))?)","objectPosition",eu),L("overscroll(-[xy])?-(auto|contain|none)",({1:e="",2:t})=>({["overscroll-behavior"+e]:t})),L("(static|fixed|absolute|relative|sticky)","position"),I("-?inset(-[xy])?(?:$|-)","inset",({1:e,_:t})=>({top:"-x"!=e&&t,right:"-y"!=e&&t,bottom:"-x"!=e&&t,left:"-y"!=e&&t})),I("-?(top|bottom|left|right)(?:$|-)","inset"),L("visible","visibility"),L("invisible",{visibility:"hidden"}),I("-?z-","zIndex"),L("flex-((row|col)(-reverse)?)","flexDirection",eg),L("flex-(wrap|wrap-reverse|nowrap)","flexWrap"),I("(flex-(?:grow|shrink))(?:$|-)"),I("(flex)-"),I("grow(?:$|-)","flexGrow"),I("shrink(?:$|-)","flexShrink"),I("basis-","flexBasis"),I("-?(order)-"),"-?(order)-(\\d+)",I("grid-cols-","gridTemplateColumns"),L("grid-cols-(\\d+)","gridTemplateColumns",eS),I("col-","gridColumn"),L("col-(span)-(\\d+)","gridColumn",e$),I("col-start-","gridColumnStart"),L("col-start-(auto|\\d+)","gridColumnStart"),I("col-end-","gridColumnEnd"),L("col-end-(auto|\\d+)","gridColumnEnd"),I("grid-rows-","gridTemplateRows"),L("grid-rows-(\\d+)","gridTemplateRows",eS),I("row-","gridRow"),L("row-(span)-(\\d+)","gridRow",e$),I("row-start-","gridRowStart"),L("row-start-(auto|\\d+)","gridRowStart"),I("row-end-","gridRowEnd"),L("row-end-(auto|\\d+)","gridRowEnd"),L("grid-flow-((row|col)(-dense)?)","gridAutoFlow",e=>eu(eg(e))),L("grid-flow-(dense)","gridAutoFlow"),I("auto-cols-","gridAutoColumns"),I("auto-rows-","gridAutoRows"),I("gap-x(?:$|-)","gap","columnGap"),I("gap-y(?:$|-)","gap","rowGap"),I("gap(?:$|-)","gap"),"(justify-(?:items|self))-",L("justify-","justifyContent",eh),L("(content|items|self)-",e=>({["align-"+e[1]]:eh(e)})),L("(place-(content|items|self))-",({1:e,$$:t})=>({[e]:("wun".includes(t[3])?"space-":"")+t})),I("p([xytrbl])?(?:$|-)","padding",ex("padding")),I("-?m([xytrbl])?(?:$|-)","margin",ex("margin")),I("-?space-(x|y)(?:$|-)","space",({1:e,_:t})=>({"&>:not([hidden])~:not([hidden])":{[`--tw-space-${e}-reverse`]:"0",["margin-"+({y:"top",x:"left"})[e]]:`calc(${t} * calc(1 - var(--tw-space-${e}-reverse)))`,["margin-"+({y:"bottom",x:"right"})[e]]:`calc(${t} * var(--tw-space-${e}-reverse))`}})),L("space-(x|y)-reverse",({1:e})=>({"&>:not([hidden])~:not([hidden])":{[`--tw-space-${e}-reverse`]:"1"}})),I("w-","width"),I("min-w-","minWidth"),I("max-w-","maxWidth"),I("h-","height"),I("min-h-","minHeight"),I("max-h-","maxHeight"),I("font-","fontWeight"),I("font-","fontFamily","fontFamily",eb),L("antialiased",{WebkitFontSmoothing:"antialiased",MozOsxFontSmoothing:"grayscale"}),L("subpixel-antialiased",{WebkitFontSmoothing:"auto",MozOsxFontSmoothing:"auto"}),L("italic","fontStyle"),L("not-italic",{fontStyle:"normal"}),L("(ordinal|slashed-zero|(normal|lining|oldstyle|proportional|tabular)-nums|(diagonal|stacked)-fractions)",({1:e,2:t="",3:r})=>"normal"==t?{fontVariantNumeric:"normal"}:{["--tw-"+(r?"numeric-fraction":"pt".includes(t[0])?"numeric-spacing":t?"numeric-figure":e)]:e,fontVariantNumeric:"var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)","@layer defaults":{"*,::before,::after,::backdrop":{"--tw-ordinal":"var(--tw-empty,/*!*/ /*!*/)","--tw-slashed-zero":"var(--tw-empty,/*!*/ /*!*/)","--tw-numeric-figure":"var(--tw-empty,/*!*/ /*!*/)","--tw-numeric-spacing":"var(--tw-empty,/*!*/ /*!*/)","--tw-numeric-fraction":"var(--tw-empty,/*!*/ /*!*/)"}}}),I("tracking-","letterSpacing"),I("leading-","lineHeight"),L("list-(inside|outside)","listStylePosition"),I("list-","listStyleType"),L("list-","listStyleType"),I("placeholder-opacity-","placeholderOpacity",({_:e})=>({"&::placeholder":{"--tw-placeholder-opacity":e}})),N("placeholder-",{property:"color",selector:"&::placeholder"}),L("text-(left|center|right|justify|start|end)","textAlign"),L("text-(ellipsis|clip)","textOverflow"),I("text-opacity-","textOpacity","--tw-text-opacity"),N("text-",{property:"color"}),I("text-","fontSize",({_:e})=>"string"==typeof e?{fontSize:e}:o({fontSize:e[0]},"string"==typeof e[1]?{lineHeight:e[1]}:e[1])),I("indent-","textIndent"),L("(overline|underline|line-through)","textDecorationLine"),L("no-underline",{textDecorationLine:"none"}),I("underline-offset-","textUnderlineOffset"),N("decoration-",{section:"textDecorationColor",opacityVariable:!1,opacitySection:"opacity"}),I("decoration-","textDecorationThickness"),L("decoration-","textDecorationStyle"),L("(uppercase|lowercase|capitalize)","textTransform"),L("normal-case",{textTransform:"none"}),L("truncate",{overflow:"hidden",whiteSpace:"nowrap",textOverflow:"ellipsis"}),L("align-","verticalAlign"),L("whitespace-","whiteSpace"),L("break-normal",{wordBreak:"normal",overflowWrap:"normal"}),L("break-words",{overflowWrap:"break-word"}),L("break-all",{wordBreak:"break-all"}),N("caret-",{opacityVariable:!1,opacitySection:"opacity"}),N("accent-",{opacityVariable:!1,opacitySection:"opacity"}),L("bg-gradient-to-([trbl]|[tb][rl])","backgroundImage",({1:e})=>`linear-gradient(to ${em(e," ")},var(--tw-gradient-stops))`),N("from-",{section:"gradientColorStops",opacityVariable:!1,opacitySection:"opacity"},({_:e})=>({"--tw-gradient-from":e.value,"--tw-gradient-to":e.color({opacityValue:"0"}),"--tw-gradient-stops":"var(--tw-gradient-from),var(--tw-gradient-to)"})),N("via-",{section:"gradientColorStops",opacityVariable:!1,opacitySection:"opacity"},({_:e})=>({"--tw-gradient-to":e.color({opacityValue:"0"}),"--tw-gradient-stops":`var(--tw-gradient-from),${e.value},var(--tw-gradient-to)`})),N("to-",{section:"gradientColorStops",property:"--tw-gradient-to",opacityVariable:!1,opacitySection:"opacity"}),L("bg-(fixed|local|scroll)","backgroundAttachment"),L("bg-origin-(border|padding|content)","backgroundOrigin",({1:e})=>e+"-box"),L(["bg-(no-repeat|repeat(-[xy])?)","bg-repeat-(round|space)"],"backgroundRepeat"),L("bg-blend-","backgroundBlendMode"),L("bg-clip-(border|padding|content|text)","backgroundClip",({1:e})=>e+("text"==e?"":"-box")),I("bg-opacity-","backgroundOpacity","--tw-bg-opacity"),N("bg-",{section:"backgroundColor"}),I("bg-","backgroundImage"),I("bg-","backgroundPosition"),L("bg-(top|bottom|center|(left|right)(-(top|bottom))?)","backgroundPosition",eu),I("bg-","backgroundSize"),I("rounded(?:$|-)","borderRadius"),I("rounded-([trbl]|[tb][rl])(?:$|-)","borderRadius",({1:e,_:t})=>{let r={t:["tl","tr"],r:["tr","br"],b:["bl","br"],l:["bl","tl"]}[e]||[e,e];return{[`border-${em(r[0])}-radius`]:t,[`border-${em(r[1])}-radius`]:t}}),L("border-(collapse|separate)","borderCollapse"),I("border-opacity(?:$|-)","borderOpacity","--tw-border-opacity"),L("border-(solid|dashed|dotted|double|none)","borderStyle"),I("border-spacing(-[xy])?(?:$|-)","borderSpacing",({1:e,_:t})=>({"@layer defaults":{"*,::before,::after,::backdrop":{"--tw-border-spacing-x":0,"--tw-border-spacing-y":0}},["--tw-border-spacing"+(e||"-x")]:t,["--tw-border-spacing"+(e||"-y")]:t,"border-spacing":"var(--tw-border-spacing-x) var(--tw-border-spacing-y)"})),N("border-([xytrbl])-",{section:"borderColor"},ex("border","Color")),N("border-"),I("border-([xytrbl])(?:$|-)","borderWidth",ex("border","Width")),I("border(?:$|-)","borderWidth"),I("divide-opacity(?:$|-)","divideOpacity",({_:e})=>({"&>:not([hidden])~:not([hidden])":{"--tw-divide-opacity":e}})),L("divide-(solid|dashed|dotted|double|none)",({1:e})=>({"&>:not([hidden])~:not([hidden])":{borderStyle:e}})),L("divide-([xy]-reverse)",({1:e})=>({"&>:not([hidden])~:not([hidden])":{["--tw-divide-"+e]:"1"}})),I("divide-([xy])(?:$|-)","divideWidth",({1:e,_:t})=>{let r={x:"lr",y:"tb"}[e];return{"&>:not([hidden])~:not([hidden])":{[`--tw-divide-${e}-reverse`]:"0",[`border-${em(r[0])}Width`]:`calc(${t} * calc(1 - var(--tw-divide-${e}-reverse)))`,[`border-${em(r[1])}Width`]:`calc(${t} * var(--tw-divide-${e}-reverse))`}}}),N("divide-",{property:"borderColor",selector:"&>:not([hidden])~:not([hidden])"}),I("ring-opacity(?:$|-)","ringOpacity","--tw-ring-opacity"),N("ring-offset-",{property:"--tw-ring-offset-color",opacityVariable:!1}),I("ring-offset(?:$|-)","ringOffsetWidth","--tw-ring-offset-width"),L("ring-inset",{"--tw-ring-inset":"inset"}),N("ring-",{property:"--tw-ring-color"}),I("ring(?:$|-)","ringWidth",({_:e},{theme:t})=>({"--tw-ring-offset-shadow":"var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)","--tw-ring-shadow":`var(--tw-ring-inset) 0 0 0 calc(${e} + var(--tw-ring-offset-width)) var(--tw-ring-color)`,boxShadow:"var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)","@layer defaults":{"*,::before,::after,::backdrop":{"--tw-ring-offset-shadow":"0 0 #0000","--tw-ring-shadow":"0 0 #0000","--tw-shadow":"0 0 #0000","--tw-shadow-colored":"0 0 #0000","&":{"--tw-ring-inset":"var(--tw-empty,/*!*/ /*!*/)","--tw-ring-offset-width":t("ringOffsetWidth","","0px"),"--tw-ring-offset-color":C(t("ringOffsetColor","","#fff")),"--tw-ring-color":C(t("ringColor","","#93c5fd"),{opacityVariable:"--tw-ring-opacity"}),"--tw-ring-opacity":t("ringOpacity","","0.5")}}}})),N("shadow-",{section:"boxShadowColor",opacityVariable:!1,opacitySection:"opacity"},({_:e})=>({"--tw-shadow-color":e.value,"--tw-shadow":"var(--tw-shadow-colored)"})),I("shadow(?:$|-)","boxShadow",({_:e})=>({"--tw-shadow":eb(e),"--tw-shadow-colored":eb(e).replace(/([^,]\s+)(?:#[a-f\d]+|(?:(?:hsl|rgb)a?|hwb|lab|lch|color|var)\(.+?\)|[a-z]+)(,|$)/g,"$1var(--tw-shadow-color)$2"),boxShadow:"var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)","@layer defaults":{"*,::before,::after,::backdrop":{"--tw-ring-offset-shadow":"0 0 #0000","--tw-ring-shadow":"0 0 #0000","--tw-shadow":"0 0 #0000","--tw-shadow-colored":"0 0 #0000"}}})),I("(opacity)-"),L("mix-blend-","mixBlendMode"),...ew(),...ew("backdrop-"),I("transition(?:$|-)","transitionProperty",(e,{theme:t})=>({transitionProperty:eb(e),transitionTimingFunction:"none"==e._?void 0:eb(t("transitionTimingFunction","")),transitionDuration:"none"==e._?void 0:eb(t("transitionDuration",""))})),I("duration(?:$|-)","transitionDuration","transitionDuration",eb),I("ease(?:$|-)","transitionTimingFunction","transitionTimingFunction",eb),I("delay(?:$|-)","transitionDelay","transitionDelay",eb),I("animate(?:$|-)","animation",(e,{theme:t,h:r})=>{let o=eb(e),n=o.split(" "),i=t("keyframes",n[0]);return i?{["@keyframes "+(n[0]=r(n[0]))]:i,animation:n.join(" ")}:{animation:o}}),"(transform)-(none)",L("transform",ev),L("transform-(cpu|gpu)",({1:e})=>({"--tw-transform":ek("gpu"==e)})),I("scale(-[xy])?-","scale",({1:e,_:t})=>o({["--tw-scale"+(e||"-x")]:t,["--tw-scale"+(e||"-y")]:t},ev())),I("-?(rotate)-","rotate",ey),I("-?(translate-[xy])-","translate",ey),I("-?(skew-[xy])-","skew",ey),L("origin-(center|((top|bottom)(-(left|right))?)|left|right)","transformOrigin",eu),"(appearance)-",I("(columns)-"),"(columns)-(\\d+)","(break-(?:before|after|inside))-",I("(cursor)-"),"(cursor)-",L("snap-(none)","scroll-snap-type"),L("snap-(x|y|both)",({1:e})=>({"scroll-snap-type":e+" var(--tw-scroll-snap-strictness)","@layer defaults":{"*,::before,::after,::backdrop":{"--tw-scroll-snap-strictness":"proximity"}}})),L("snap-(mandatory|proximity)","--tw-scroll-snap-strictness"),L("snap-(?:(start|end|center)|align-(none))","scroll-snap-align"),L("snap-(normal|always)","scroll-snap-stop"),L("scroll-(auto|smooth)","scroll-behavior"),I("scroll-p([xytrbl])?(?:$|-)","padding",ex("scroll-padding")),I("-?scroll-m([xytrbl])?(?:$|-)","scroll-margin",ex("scroll-margin")),L("touch-(auto|none|manipulation)","touch-action"),L("touch-(pinch-zoom|pan-(?:(x|left|right)|(y|up|down)))",({1:e,2:t,3:r})=>({[`--tw-${t?"pan-x":r?"pan-y":e}`]:e,"touch-action":"var(--tw-touch-action)","@layer defaults":{"*,::before,::after,::backdrop":{"--tw-pan-x":"var(--tw-empty,/*!*/ /*!*/)","--tw-pan-y":"var(--tw-empty,/*!*/ /*!*/)","--tw-pinch-zoom":"var(--tw-empty,/*!*/ /*!*/)","--tw-touch-action":"var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom)"}}})),L("outline-none",{outline:"2px solid transparent","outline-offset":"2px"}),L("outline",{outlineStyle:"solid"}),L("outline-(dashed|dotted|double|hidden)","outlineStyle"),I("(outline-offset)-"),N("outline-",{opacityVariable:!1,opacitySection:"opacity"}),I("outline-","outlineWidth"),"(pointer-events)-",I("(will-change)-"),"(will-change)-",["resize(?:-(none|x|y))?","resize",({1:e})=>({x:"horizontal",y:"vertical"})[e]||e||"both"],L("select-(none|text|all|auto)","userSelect"),N("fill-",{section:"fill",opacityVariable:!1,opacitySection:"opacity"}),N("stroke-",{section:"stroke",opacityVariable:!1,opacitySection:"opacity"}),I("stroke-","strokeWidth"),L("sr-only",{position:"absolute",width:"1px",height:"1px",padding:"0",margin:"-1px",overflow:"hidden",whiteSpace:"nowrap",clip:"rect(0,0,0,0)",borderWidth:"0"}),L("not-sr-only",{position:"static",width:"auto",height:"auto",padding:"0",margin:"0",overflow:"visible",whiteSpace:"normal",clip:"auto"})];function eu(e){return("string"==typeof e?e:e[1]).replace(/-/g," ").trim()}function eg(e){return("string"==typeof e?e:e[1]).replace("col","column")}function em(e,t="-"){let r=[];for(let o of e)r.push({t:"top",r:"right",b:"bottom",l:"left"}[o]);return r.join(t)}function eb(e){return e&&""+(e._||e)}function eh({$$:e}){return(({r:"flex-","":"flex-",w:"space-",u:"space-",n:"space-"})[e[3]||""]||"")+e}function ex(e,t=""){return({1:r,_:n})=>{let i={x:"lr",y:"tb"}[r]||r+r;return i?o({},B(e+"-"+em(i[0])+t,n),B(e+"-"+em(i[1])+t,n)):B(e+t,n)}}function ew(e=""){let t=["blur","brightness","contrast","grayscale","hue-rotate","invert",e&&"opacity","saturate","sepia",!e&&"drop-shadow"].filter(Boolean),r={};for(let n of t)r[`--tw-${e}${n}`]="var(--tw-empty,/*!*/ /*!*/)";return r={[`${e}filter`]:t.map(t=>`var(--tw-${e}${t})`).join(" "),"@layer defaults":{"*,::before,::after,::backdrop":r}},[`(${e}filter)-(none)`,L(`${e}filter`,r),...t.map(t=>I(`${"h"==t[0]?"-?":""}(${e}${t})(?:$|-)`,t,({1:e,_:n})=>o({[`--tw-${e}`]:c(n).map(e=>`${t}(${e})`).join(" ")},r)))]}function ey({1:e,_:t}){return o({["--tw-"+e]:t},ev())}function ev(){return{transform:"var(--tw-transform)","@layer defaults":{"*,::before,::after,::backdrop":{"--tw-translate-x":"0","--tw-translate-y":"0","--tw-rotate":"0","--tw-skew-x":"0","--tw-skew-y":"0","--tw-scale-x":"1","--tw-scale-y":"1","--tw-transform":ek()}}}}function ek(e){return[e?"translate3d(var(--tw-translate-x),var(--tw-translate-y),0)":"translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y))","rotate(var(--tw-rotate))","skewX(var(--tw-skew-x))","skewY(var(--tw-skew-y))","scaleX(var(--tw-scale-x))","scaleY(var(--tw-scale-y))"].join(" ")}function e$({1:e,2:t}){return`${e} ${t} / ${e} ${t}`}function eS({1:e}){return`repeat(${e},minmax(0,1fr))`}let eC=[["sticky","@supports ((position: -webkit-sticky) or (position:sticky))"],["motion-reduce","@media (prefers-reduced-motion:reduce)"],["motion-safe","@media (prefers-reduced-motion:no-preference)"],["print","@media print"],["portrait","@media (orientation:portrait)"],["landscape","@media (orientation:landscape)"],["contrast-more","@media (prefers-contrast:more)"],["contrast-less","@media (prefers-contrast:less)"],["marker","& *::marker,&::marker"],["selection","& *::selection,&::selection"],["first-letter","&::first-letter"],["first-line","&::first-line"],["file","&::file-selector-button"],["placeholder","&::placeholder"],["backdrop","&::backdrop"],["first","&:first-child"],["last","&:last-child"],["even","&:nth-child(2n)"],["odd","&:nth-child(odd)"],["open","&[open]"],["((group|peer)(~[^-[]+)?)(-[a-z-]+|-\\[(.+)]|\\[.+])",({1:e,4:t,5:r},{e:o,h:n,v:i})=>{let a=r&&H(r)||("["==t[0]?t:i(t.slice(1)));return`${(a.includes("&")?a:"&"+a).replace(/&/g,`:merge(.${o(n(e))})`)}${"p"==e[0]?"~":" "}&`}],["(ltr|rtl)",({1:e})=>`[dir="${e}"] &`],[/^\[(.+)]$/,({1:e})=>/[&@]/.test(e)&&H(e).replace(/[}]+$/,"").split("{")]],eA=function(e){if(document.currentScript){let t=()=>r.disconnect(),r=new MutationObserver(r=>{for(let{target:o}of r)if(o===document.body)return e(),t()});return r.observe(document.documentElement,{childList:!0,subtree:!0}),t}return f}(ez);function ez(e={},r){var{disablePreflight:i}=e,s=n(e,["disablePreflight"]);return eA(),function(e,r=!0){var i;let s=W(e);return function(e={},r=ee,i){return null==t||t.destroy(),t=function(e=er,t=document.documentElement){if(!t)return e;let r=new MutationObserver(n);r.observe(t,{attributeFilter:["class"],subtree:!0,childList:!0}),i(t),n([{target:t,type:""}]);let{destroy:o}=e;return e.destroy=()=>{r.disconnect(),o.call(e)},e;function n(e){for(let{type:t,target:o}of e)if("a"==t[0])i(o);else for(let n of o.querySelectorAll("[class]"))i(n);r.takeRecords()}function i(t){var r,o;let n;let i=t.getAttribute("class");i&&(r=i)!=(o=n=e(i))&&""+r.split(" ").sort()!=""+o.split(" ").sort()&&t.setAttribute("class",n)}}(function(e,t){let r=W(e),i=function({theme:e,darkMode:t,darkColor:r,variants:o,rules:i,hash:s,stringify:f,ignorelist:p}){let u=new Map,g=new Map,m=new Map,b=new Map,h=X(p,(e,t)=>t.test(e));o.push(["dark",Array.isArray(t)||"class"==t?`${c(t)[1]||".dark"} &`:"string"==typeof t&&"media"!=t?t:"@media (prefers-color-scheme:dark)"]);let x="function"==typeof s?e=>s(e,l):s?l:d;return{theme:function(e){var{extend:t={}}=e,r=n(e,["extend"]);let o={},i={get colors(){return a("colors")},theme:a,negative:()=>({}),breakpoints(e){let t={};for(let r in e)"string"==typeof e[r]&&(t["screen-"+r]=e[r]);return t}};return a;function a(e,n,i,s){if(e){var c;if({1:e,2:s}=/^(\S+?)(?:\s*\/\s*([^/]+))?$/.exec(e)||[,e],/[.[]/.test(e)){let d=[];e.replace(/\[([^\]]+)\]|([^.[]+)/g,(e,t,r=t)=>d.push(r)),e=d.shift(),i=n,n=d.join("-")}let f=o[e]||Object.assign(Object.assign(o[e]={},l(r,e)),l(t,e));if(null==n)return f;let p=null!=(c=f[n||"DEFAULT"])?c:i;return s?C(p,{opacityValue:z(s,a)}):p}let u={};for(let g of[...Object.keys(r),...Object.keys(t)])u[g]=a(g);return u}function l(e,t){let r=e[t];return("function"==typeof r&&(r=r(i)),r&&/color|fill|stroke/i.test(t))?function e(t,r=[]){let o={};for(let n in t){let i=t[n],a=[...r,n];o[a.join("-")]=i,"DEFAULT"==n&&(a=r,o[r.join("-")]=i),"object"==typeof i&&Object.assign(o,e(i,a))}return o}(r):r}}(e),e:a,h:x,s(e,t){return f(K(e,x),K(t,x),this)},d(e,t,o){return null==r?void 0:r(e,t,this,o)},v(e){return u.has(e)||u.set(e,q(e,o,g,G,this)||"&:"+e),u.get(e)},r(e,t){let r=JSON.stringify([e,t]);return m.has(r)||m.set(r,!h(e,this)&&q(e,i,b,Y,this,t)),m.get(r)}}}(r),s=new Map,f=[],u=new Set;function g(e){let r=e.n&&i.h(e.n),n=x(r?o({},e,{n:r}):e);if(n&&!u.has(n)){u.add(n);let a=k(f,e);t.insert(n,a,e),f.splice(a,0,e)}return r}return t.resume(e=>s.set(e,e),(e,r)=>{t.insert(e,f.length,r),f.push(r),u.add(e)}),Object.defineProperties(function(e){if(!s.size)for(let t of c(r.preflight))"function"==typeof t&&(t=t(i)),t&&("string"==typeof t?T("",p.b,D(t),i,p.b,[],!1,!0):A(t,{},i,p.b)).forEach(g);e=""+e;let o=s.get(e);if(!o){let n=new Set;for(let a of j(D(e),i))n.add(a.c).add(g(a));o=[...n].filter(Boolean).join(" "),s.set(e,o).set(o,o)}return o},Object.getOwnPropertyDescriptors({get target(){return t.target},theme:i.theme,config:r,snapshot(){let e=t.snapshot(),r=new Set(u),o=new Map(s),n=[...f];return()=>{e(),u=r,s=o,f=n}},clear(){t.clear(),u=new Set,s=new Map,f=[]},destroy(){this.clear(),t.destroy()}}))}(e,"function"==typeof r?r():r),void 0)}(o({},s,{hash:null!=(i=s.hash)?i:r}),()=>ee(!r))}(W(o({},s,{presets:[({stringify:e})=>({stringify(t,r,o){var n,i;let a="",l=eo.get(t);l&&(a+=e(l,r,o)+";");let s=(n=/^(?:(text-(?:decoration$|e|or|si)|back(?:ground-cl|d|f)|box-d|mask(?:$|-[ispro]|-cl)|pr|hyphena|flex-d)|(tab-|column(?!-s)|text-align-l)|(ap)|u|hy)/i.exec(t))?n[1]?1:n[2]?2:n[3]?3:5:0,c=(i=/^(?:(pos)|(cli)|(background-i)|(flex(?:$|-b)|(?:max-|min-)?(?:block-s|inl|he|widt))|dis)/i.exec(t))?i[1]?/^sti/i.test(r)?1:0:i[2]?/^pat/i.test(r)?1:0:i[3]?/^image-/i.test(r)?1:0:i[4]?"-"===r[3]?2:0:/^(?:inline-)?grid$/i.test(r)?4:0:0;for(let d of en)s&d[1]&&(a+=e(d[0]+t,r,o)+";"),c&d[1]&&(a+=e(t,d[0]+r,o)+";");return a+e(t,r,o)}}),function({disablePreflight:e}={}){return{preflight:e?void 0:ef,theme:ea,variants:eC,rules:ep}}({disablePreflight:i}),...c(s.presets)]})),r)}return e.install=ez,e.presetTailwind_colors=ei,e.presetTailwind_defaultTheme=ea,e}({});//# sourceMappingURL=cdn.global.js.map +var twind=function(e){"use strict";let t;function r(){return(r=Object.assign||function(e){for(var t=1;t=0||(n[r]=e[r]);return n}function i(e){return[...e.v,(e.i?"!":"")+e.n].join(":")}let a="undefined"!=typeof CSS&&CSS.escape||(e=>e.replace(/[!"'`*+.,;:\\/<=>?@#$%&^|~()[\]{}]/g,"\\$&").replace(/^\d/,"\\3$& "));function l(e){for(var t=9,r=e.length;r--;)t=Math.imul(t^e.charCodeAt(r),1597334677);return"#"+((t^t>>>9)>>>0).toString(36)}function s(e,t="@media "){return t+c(e).map(e=>("string"==typeof e&&(e={min:e}),e.raw||Object.keys(e).map(t=>`(${t}-width:${e[t]})`).join(" and "))).join(",")}function c(e=[]){return Array.isArray(e)?e:null==e?[]:[e]}function d(e){return e}function f(){}let p={d:0,b:134217728,c:268435456,a:671088640,u:805306368,o:939524096};function u(e){var t;return(null==(t=e.match(/[-=:;]/g))?void 0:t.length)||0}function g(e){return Math.min(/(?:^|width[^\d]+)(\d+(?:.\d+)?)(p)?/.test(e)?Math.max(0,29.63*(+RegExp.$1/(RegExp.$2?15:1))**.137-43):0,15)<<22|Math.min(u(e),15)<<18}let m=["rst-c","st-ch","h-chi","y-lin","nk","sited","ecked","pty","ad-on","cus-w","ver","cus","cus-v","tive","sable","tiona","quire"];function b({n:e,i:t,v:r=[]},o,n,a){for(let l of(e&&(e=i({n:e,i:t,v:r})),a=[...c(a)],r)){let d=o.theme("screens",l);for(let f of c(d&&s(d)||o.v(l))){var p;a.push(f),n|=d?67108864|g(f):"dark"==l?1073741824:"@"==f[0]?g(f):(p=f,1<<~(/:([a-z-]+)/.test(p)&&~m.indexOf(RegExp.$1.slice(2,7))||-18))}}return{n:e,p:n,r:a,i:t}}let h=new Map;function x(e){if(e.d){let t=[],r=w(e.r.reduce((e,r)=>"@"==r[0]?(t.push(r),e):r?w(e,e=>w(r,t=>{let r=/(:merge\(.+?\))(:[a-z-]+|\\[.+])/.exec(t);if(r){let o=e.indexOf(r[1]);return~o?e.slice(0,o)+r[0]+e.slice(o+r[1].length):y(e,t)}return y(t,e)})):e,"&"),t=>y(t,e.n?"."+a(e.n):""));return r&&t.push(r.replace(/:merge\((.+?)\)/g,"$1")),t.reduceRight((e,t)=>t+"{"+e+"}",e.d)}}function w(e,t){return e.replace(/ *((?:\(.+?\)|\[.+?\]|[^,])+) *(,|$)/g,(e,r,o)=>t(r)+o)}function y(e,t){return e.replace(/&/g,t)}let v=new Intl.Collator("en",{numeric:!0});function k(e,t){for(var r=0,o=e.length;r>1;0>=$(e[n],t)?r=n+1:o=n}return o}function $(e,t){let r=e.p&p.o;return r==(t.p&p.o)&&(r==p.b||r==p.o)?0:e.p-t.p||e.o-t.o||v.compare(S(e.n),S(t.n))||v.compare(C(e.n),C(t.n))}function S(e){return(e||"").split(/:/).pop().split("/").pop()||"\0"}function C(e){return(e||"").replace(/\W/g,e=>String.fromCharCode(127+e.charCodeAt(0)))+"\0"}function A(e,t){return Math.round(parseInt(e,16)*t)}function z(e,t={}){if("function"==typeof e)return e(t);let{opacityValue:r="1",opacityVariable:o}=t,n=o?`var(${o})`:r;if(e.includes(""))return e.replace("",n);if("#"==e[0]&&(4==e.length||7==e.length)){let i=(e.length-1)/3,a=[17,1,.062272][i-1];return`rgba(${[A(e.substr(1,i),a),A(e.substr(1+i,i),a),A(e.substr(1+2*i,i),a),n]})`}return"1"==n?e:"0"==n?"#0000":e.replace(/^(rgb|hsl)(\([^)]+)\)$/,`$1a$2,${n})`)}function O(e,t,r,o,n=[]){return function e(t,{n:r,p:o,r:n=[],i:i},a){let d=[],f="",m=0,b=0;for(let h in t||{}){var w,y;let v=t[h];if("@"==h[0]){if(!v)continue;if("a"==h[1]){d.push(...W(r,o,M(""+v),a,o,n,i,!0));continue}if("l"==h[1]){for(let k of c(v))d.push(...e(k,{n:r,p:(w=p[h[7]],o&~p.o|w),r:n,i:i},a));continue}if("i"==h[1]){d.push(...c(v).map(e=>({p:-1,o:0,r:[],d:h+" "+e})));continue}if("k"==h[1]){d.push({p:p.d,o:0,r:[h],d:e(v,{p:p.d},a).map(x).join("")});continue}if("f"==h[1]){d.push(...c(v).map(t=>({p:p.d,o:0,r:[h],d:e(t,{p:p.d},a).map(x).join("")})));continue}}if("object"!=typeof v||Array.isArray(v))"label"==h&&v?r=v+l(JSON.stringify([o,i,t])):(v||0===v)&&(h=h.replace(/[A-Z]/g,e=>"-"+e.toLowerCase()),b+=1,m=Math.max(m,"-"==(y=h)[0]?0:u(y)+(/^(?:(border-(?!w|c|sty)|[tlbr].{2,4}m?$|c.{7,8}$)|([fl].{5}l|g.{8}$|pl))/.test(y)?+!!RegExp.$1||-!!RegExp.$2:0)+1),f+=(f?";":"")+c(v).map(e=>a.s(h,j(""+e,a.theme)+(i?" !important":""))).join(";"));else if("@"==h[0]||h.includes("&")){let S=o;"@"==h[0]&&(h=h.replace(/\bscreen\(([^)]+)\)/g,(e,t)=>{let r=a.theme("screens",t);return r?(S|=67108864,s(r,"")):e}),S|=g(h)),d.push(...e(v,{n:r,p:S,r:[...n,h],i:i},a))}else d.push(...e(v,{p:o,r:[...n,h]},a))}return d.unshift({n:r,p:o,o:Math.max(0,15-b)+1.5*Math.min(m||15,15),r:n,d:f}),d.sort($)}(e,b(t,r,o,n),r)}function j(e,t){return e.replace(/theme\((["'`])?(.+?)\1(?:\s*,\s*(["'`])?(.+?)\3)?\)/g,(e,r,o,n,i)=>{let a=t(o,i);return"function"==typeof a&&/color|fill|stroke/i.test(o)?z(a):""+a})}function T(e,t){let r;let n=[];for(let i of e)i.d&&i.n?(null==r?void 0:r.p)==i.p&&""+r.r==""+i.r?(r.c=[r.c,i.c].filter(Boolean).join(" "),r.d=r.d+";"+i.d):n.push(r=o({},i,{n:i.n&&t})):n.push(o({},i,{n:i.n&&t}));return n}function F(e,t,r=p.u,n,a){let l=[];for(let s of e)for(let d of function(e,t,r,n,a){var l;e=o({},e,{i:e.i||a});let s=function(e,t){let r=h.get(e.n);return r?r(e,t):t.r(e.n,"dark"==e.v[0])}(e,t);return s?"string"==typeof s?({r:n,p:r}=b(e,t,r,n),T(F(M(s),t,r,n,e.i),e.n)):Array.isArray(s)?s.map(e=>{var t,i;return o({o:0},e,{r:[...c(n),...c(e.r)],p:(t=r,i=null!=(l=e.p)?l:r,t&~p.o|i)})}):O(s,e,t,r,n):[{c:i(e),p:0,o:0,r:[]}]}(s,t,r,n,a))l.splice(k(l,d),0,d);return l}function W(e,t,r,n,i,a,l,s){return T((s?r.flatMap(e=>F([e],n,i,a,l)):F(r,n,i,a,l)).map(e=>e.p&p.o&&(e.n||t==p.b)?o({},e,{p:e.p&~p.o|t,o:0}):e),e)}function D(e,t){if("("!=e[e.length-1]){let r=[],o=!1,n=!1,i="";for(let a of e)if(!("("==a||/[~@]$/.test(a))){if("!"==a[0]&&(a=a.slice(1),o=!o),a.endsWith(":")){r["dark:"==a?"unshift":"push"](a.slice(0,-1));continue}"-"==a[0]&&(a=a.slice(1),n=!n),a.endsWith("-")&&(a=a.slice(0,-1)),a&&"&"!=a&&(i+=(i&&"-")+a)}i&&(n&&(i="-"+i),t[0].push({n:i,v:r.filter(E),i:o}))}}function E(e,t,r){return r.indexOf(e)==t}let R=new Map;function M(e){let t=R.get(e);if(!t){let r=[],o=[[]],n=0,a=0,s=null,c=0,d=(t,i=0)=>{n!=c&&(r.push(e.slice(n,c+i)),t&&D(r,o)),n=c+1};for(;c{let{n:i,p:a,r:l,i:s}=b(e,n,t);return r&&W(i,t,r,n,a,l,s,o)},h.set(e,n),e}(g.length>1?g.slice(0,-1)+l(JSON.stringify([g,m])):g+"("+function(e,t=","){return e.map(i).join(t)}(m)+")",p.a,m,/@$/.test(g))],o)}u=r.lastIndexOf("(",u-1)}r.length=u+1}else/[~@]/.test(f)&&"("==e[c+1]&&o.unshift([])}d(!0),R.set(e,t=o[0])}return t}function L(e,t,r){return[e,V(t,r)]}function V(e,t){return"function"==typeof e?e:"string"==typeof e&&/^[\w-]+$/.test(e)?(r,o)=>({[e]:t?t(r,o):U(r,1)}):t=>e||{[t[1]]:U(t,2)}}function U(e,t,r=e.slice(t).find(Boolean)||e.$$||e.input){return"-"==e.input[0]?`calc(${r} * -1)`:r}function I(e,t,r,o){return[e,function(e,t,r){let o="string"==typeof t?(e,o)=>({[t]:r?r(e,o):e._}):t||(({1:e,_:t},r,o)=>({[e||o]:t}));return(t,r)=>{var n;let i=P(e||t[1]),a=null!=(n=r.theme(i,t.$$))?n:_(t.$$,i,r);if(null!=a)return t._=U(t,0,a),o(t,r,i)}}(t,r,o)]}function N(e,t={},r){return[e,function(e={},t){return(r,o)=>{let{section:n=P(r[0]).replace("-","")+"Color"}=e,[i,a]=(r.$$.match(/^(\[[^\]]+]|[^/]+?)(?:\/(.+))?$/)||[]).slice(1);if(!i)return;let l=o.theme(n,i)||_(i,n,o);if(!l||"object"==typeof l)return;let{opacityVariable:s=`--tw-${r[0].replace(/-$/,"")}-opacity`,opacitySection:c=n.replace("Color","Opacity"),property:d=n,selector:f}=e,p=o.theme(c,a||"DEFAULT")||a&&_(a,c,o),u=t||(({_:e})=>{let t=B(d,e);return f?{[f]:t}:t});r._={value:z(l,{opacityVariable:s||void 0,opacityValue:p||void 0}),color:e=>z(l,e),opacityVariable:s||void 0,opacityValue:p||void 0};let g=u(r,o);if(!r.dark){let m=o.d(n,i,l);m&&m!==l&&(r._={value:z(m,{opacityVariable:s||void 0,opacityValue:p||"1"}),color:e=>z(m,e),opacityVariable:s||void 0,opacityValue:p||void 0},g={"&":g,[o.v("dark")]:u(r,o)})}return g}}(t,r)]}function B(e,t){let r={};return"string"==typeof t?r[e]=t:(t.opacityVariable&&t.value.includes(t.opacityVariable)&&(r[t.opacityVariable]=t.opacityValue||"1"),r[e]=t.value),r}function _(e,t,r){if("["==e[0]&&"]"==e.slice(-1)&&(e=H(j(e.slice(1,-1),r.theme)),!(/color|fill|stroke/i.test(t)&&!(/^color:/.test(e)||/^(#|((hsl|rgb)a?|hwb|lab|lch|color)\(|[a-z]+$)/.test(e))||/image/i.test(t)&&!(/^image:/.test(e)||/^[a-z-]+\(/.test(e))||/weight/i.test(t)&&!(/^(number|any):/.test(e)||/^\d+$/.test(e))||/position/i.test(t)&&/^(length|size):/.test(e))))return e.replace(/^[a-z-]+:/,"")}function P(e){return e.replace(/-./g,e=>e[1].toUpperCase())}function H(e){return e.includes("url(")?e.replace(/(.*?)(url\(.*?\))(.*?)/g,(e,t="",r,o="")=>H(t)+r+H(o)):e.replace(/(^|[^\\])_+/g,(e,t)=>t+" ".repeat(e.length-t.length)).replace(/\\_/g,"_").replace(/(calc|min|max|clamp)\(.+\)/g,e=>e.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g,"$1 $2 "))}function q(e){var{presets:t=[]}=e,r=n(e,["presets"]);let i={preflight:!1!==r.preflight&&[],darkMode:void 0,darkColor:void 0,theme:{},variants:c(r.variants),rules:c(r.rules),ignorelist:c(r.ignorelist),hash:r.hash,stringify:r.stringify||G};for(let a of c([...t,{darkMode:r.darkMode,darkColor:r.darkColor,preflight:!1!==r.preflight&&c(r.preflight),theme:r.theme,hash:r.hash,stringify:r.stringify}])){let{preflight:l,darkMode:s=i.darkMode,darkColor:d=i.darkColor,theme:f,variants:p,rules:u,ignorelist:g,hash:m=i.hash,stringify:b=i.stringify}="function"==typeof a?a(i):a;i={preflight:!1!==i.preflight&&!1!==l&&[...i.preflight,...c(l)],darkMode:s,darkColor:d,theme:o({},i.theme,f,{extend:o({},i.theme.extend,null==f?void 0:f.extend)}),variants:[...i.variants,...c(p)],rules:[...i.rules,...c(u)],ignorelist:[...i.ignorelist,...c(g)],hash:m,stringify:b}}return i}function G(e,t){return e+":"+t}function Y(e,t,r,o,n,i){for(let a of t){let l=r.get(a);l||r.set(a,l=o(a));let s=l(e,n,i);if(s)return s}}function J(e){var t;return Z(e[0],"function"==typeof(t=e[1])?t:()=>t)}function X(e){var t,r;return Array.isArray(e)?Z(e[0],V(e[1],e[2])):Z(e,V(t,r))}function Z(e,t){return K(e,(e,r,o,n)=>{let i=r.exec(e);if(i)return i.$$=e.slice(i[0].length),i.dark=n,t(i,o)})}function K(e,t){let r=c(e).map(Q);return(e,o,n)=>{for(let i of r){let a=t(e,i,o,n);if(a)return a}}}function Q(e){return"string"==typeof e?RegExp("^"+e+(e.includes("$")||"-"==e.slice(-1)?"":"$")):e}function ee(e,t){return e.replace(/--(tw(?:-[\w-]+)?)\b/g,(e,r)=>"--"+t(r).replace("#",""))}function et(e){let t=document.querySelector(e||"style[data-twind]");return t&&"STYLE"==t.tagName||((t=document.createElement("style")).dataset.twind="",document.head.prepend(t)),t}function er(e,t){let r=e?function(e){let t=e&&"string"!=typeof e?e:et(e);return{target:t,snapshot(){let e=Array.from(t.childNodes,e=>e.textContent);return()=>{this.clear(),e.forEach(this.insert)}},clear(){t.textContent=""},destroy(){t.remove()},insert(e,r){t.insertBefore(document.createTextNode(e),t.childNodes[r]||null)},resume:f}}():function(e){let t=(null==e?void 0:e.cssRules)?e:(e&&"string"!=typeof e?e:et(e)).sheet;return{target:t,snapshot(){let e=Array.from(t.cssRules,e=>e.cssText);return()=>{this.clear(),e.forEach(this.insert)}},clear(){for(let e=t.cssRules.length;e--;)t.deleteRule(e)},destroy(){var e;null==(e=t.ownerNode)||e.remove()},insert(e,r){try{t.insertRule(e,r)}catch(o){t.insertRule(":root{}",r),/:-[mwo]/.test(e)}},resume:f}}();return t||(r.resume=eo),r}function eo(e,t){var r,o;let n=((r=this.target).ownerNode||r).textContent||(r.cssRules?Array.from(r.cssRules,e=>e.cssText):c(r)).join(""),i=/\/\*!([\da-z]+),([\da-z]+)(?:,(.+?))?\*\//g;if(i.test(n)){let a;for(let l of(i.lastIndex=0,this.clear(),document.querySelectorAll("[class]")))e(l.getAttribute("class"));for(;o=i.exec(n),a&&t(n.slice(a.index+a[0].length,null==o?void 0:o.index),{p:parseInt(a[1],36),o:parseInt(a[2],36)/2,n:a[3]}),a=o;);}}let en=new Proxy(f,{apply:(e,r,o)=>t(o[0]),get(e,r){let o=t[r];return"function"==typeof o?function(){return o.apply(t,arguments)}:o}});var ei=new Map([["align-self","-ms-grid-row-align"],["color-adjust","-webkit-print-color-adjust"],["column-gap","grid-column-gap"],["forced-color-adjust","-ms-high-contrast-adjust"],["gap","grid-gap"],["grid-template-columns","-ms-grid-columns"],["grid-template-rows","-ms-grid-rows"],["justify-self","-ms-grid-column-align"],["margin-inline-end","-webkit-margin-end"],["margin-inline-start","-webkit-margin-start"],["mask-border","-webkit-mask-box-image"],["mask-border-outset","-webkit-mask-box-image-outset"],["mask-border-slice","-webkit-mask-box-image-slice"],["mask-border-source","-webkit-mask-box-image-source"],["mask-border-repeat","-webkit-mask-box-image-repeat"],["mask-border-width","-webkit-mask-box-image-width"],["overflow-wrap","word-wrap"],["padding-inline-end","-webkit-padding-end"],["padding-inline-start","-webkit-padding-start"],["print-color-adjust","color-adjust"],["row-gap","grid-row-gap"],["scroll-margin-bottom","scroll-snap-margin-bottom"],["scroll-margin-left","scroll-snap-margin-left"],["scroll-margin-right","scroll-snap-margin-right"],["scroll-margin-top","scroll-snap-margin-top"],["scroll-margin","scroll-snap-margin"],["text-combine-upright","-ms-text-combine-horizontal"]]);let ea=[["-webkit-",1],["-moz-",2],["-ms-",4]],el={__proto__:null,inherit:"inherit",current:"currentColor",transparent:"transparent",black:"#000",white:"#fff",slate:{50:"#f8fafc",100:"#f1f5f9",200:"#e2e8f0",300:"#cbd5e1",400:"#94a3b8",500:"#64748b",600:"#475569",700:"#334155",800:"#1e293b",900:"#0f172a"},gray:{50:"#f9fafb",100:"#f3f4f6",200:"#e5e7eb",300:"#d1d5db",400:"#9ca3af",500:"#6b7280",600:"#4b5563",700:"#374151",800:"#1f2937",900:"#111827"},zinc:{50:"#fafafa",100:"#f4f4f5",200:"#e4e4e7",300:"#d4d4d8",400:"#a1a1aa",500:"#71717a",600:"#52525b",700:"#3f3f46",800:"#27272a",900:"#18181b"},neutral:{50:"#fafafa",100:"#f5f5f5",200:"#e5e5e5",300:"#d4d4d4",400:"#a3a3a3",500:"#737373",600:"#525252",700:"#404040",800:"#262626",900:"#171717"},stone:{50:"#fafaf9",100:"#f5f5f4",200:"#e7e5e4",300:"#d6d3d1",400:"#a8a29e",500:"#78716c",600:"#57534e",700:"#44403c",800:"#292524",900:"#1c1917"},red:{50:"#fef2f2",100:"#fee2e2",200:"#fecaca",300:"#fca5a5",400:"#f87171",500:"#ef4444",600:"#dc2626",700:"#b91c1c",800:"#991b1b",900:"#7f1d1d"},orange:{50:"#fff7ed",100:"#ffedd5",200:"#fed7aa",300:"#fdba74",400:"#fb923c",500:"#f97316",600:"#ea580c",700:"#c2410c",800:"#9a3412",900:"#7c2d12"},amber:{50:"#fffbeb",100:"#fef3c7",200:"#fde68a",300:"#fcd34d",400:"#fbbf24",500:"#f59e0b",600:"#d97706",700:"#b45309",800:"#92400e",900:"#78350f"},yellow:{50:"#fefce8",100:"#fef9c3",200:"#fef08a",300:"#fde047",400:"#facc15",500:"#eab308",600:"#ca8a04",700:"#a16207",800:"#854d0e",900:"#713f12"},lime:{50:"#f7fee7",100:"#ecfccb",200:"#d9f99d",300:"#bef264",400:"#a3e635",500:"#84cc16",600:"#65a30d",700:"#4d7c0f",800:"#3f6212",900:"#365314"},green:{50:"#f0fdf4",100:"#dcfce7",200:"#bbf7d0",300:"#86efac",400:"#4ade80",500:"#22c55e",600:"#16a34a",700:"#15803d",800:"#166534",900:"#14532d"},emerald:{50:"#ecfdf5",100:"#d1fae5",200:"#a7f3d0",300:"#6ee7b7",400:"#34d399",500:"#10b981",600:"#059669",700:"#047857",800:"#065f46",900:"#064e3b"},teal:{50:"#f0fdfa",100:"#ccfbf1",200:"#99f6e4",300:"#5eead4",400:"#2dd4bf",500:"#14b8a6",600:"#0d9488",700:"#0f766e",800:"#115e59",900:"#134e4a"},cyan:{50:"#ecfeff",100:"#cffafe",200:"#a5f3fc",300:"#67e8f9",400:"#22d3ee",500:"#06b6d4",600:"#0891b2",700:"#0e7490",800:"#155e75",900:"#164e63"},sky:{50:"#f0f9ff",100:"#e0f2fe",200:"#bae6fd",300:"#7dd3fc",400:"#38bdf8",500:"#0ea5e9",600:"#0284c7",700:"#0369a1",800:"#075985",900:"#0c4a6e"},blue:{50:"#eff6ff",100:"#dbeafe",200:"#bfdbfe",300:"#93c5fd",400:"#60a5fa",500:"#3b82f6",600:"#2563eb",700:"#1d4ed8",800:"#1e40af",900:"#1e3a8a"},indigo:{50:"#eef2ff",100:"#e0e7ff",200:"#c7d2fe",300:"#a5b4fc",400:"#818cf8",500:"#6366f1",600:"#4f46e5",700:"#4338ca",800:"#3730a3",900:"#312e81"},violet:{50:"#f5f3ff",100:"#ede9fe",200:"#ddd6fe",300:"#c4b5fd",400:"#a78bfa",500:"#8b5cf6",600:"#7c3aed",700:"#6d28d9",800:"#5b21b6",900:"#4c1d95"},purple:{50:"#faf5ff",100:"#f3e8ff",200:"#e9d5ff",300:"#d8b4fe",400:"#c084fc",500:"#a855f7",600:"#9333ea",700:"#7e22ce",800:"#6b21a8",900:"#581c87"},fuchsia:{50:"#fdf4ff",100:"#fae8ff",200:"#f5d0fe",300:"#f0abfc",400:"#e879f9",500:"#d946ef",600:"#c026d3",700:"#a21caf",800:"#86198f",900:"#701a75"},pink:{50:"#fdf2f8",100:"#fce7f3",200:"#fbcfe8",300:"#f9a8d4",400:"#f472b6",500:"#ec4899",600:"#db2777",700:"#be185d",800:"#9d174d",900:"#831843"},rose:{50:"#fff1f2",100:"#ffe4e6",200:"#fecdd3",300:"#fda4af",400:"#fb7185",500:"#f43f5e",600:"#e11d48",700:"#be123c",800:"#9f1239",900:"#881337"}},es={screens:{sm:"640px",md:"768px",lg:"1024px",xl:"1280px","2xl":"1536px"},colors:el,columns:{auto:"auto","3xs":"16rem","2xs":"18rem",xs:"20rem",sm:"24rem",md:"28rem",lg:"32rem",xl:"36rem","2xl":"42rem","3xl":"48rem","4xl":"56rem","5xl":"64rem","6xl":"72rem","7xl":"80rem"},spacing:o({px:"1px",0:"0px"},ef(4,"rem",4,.5,.5),ef(12,"rem",4,5),{14:"3.5rem"},ef(64,"rem",4,16,4),{72:"18rem",80:"20rem",96:"24rem"}),durations:{75:"75ms",100:"100ms",150:"150ms",200:"200ms",300:"300ms",500:"500ms",700:"700ms",1e3:"1000ms"},animation:{none:"none",spin:"spin 1s linear infinite",ping:"ping 1s cubic-bezier(0,0,0.2,1) infinite",pulse:"pulse 2s cubic-bezier(0.4,0,0.6,1) infinite",bounce:"bounce 1s infinite"},aspectRatio:{auto:"auto",square:"1/1",video:"16/9"},backdropBlur:ep("blur"),backdropBrightness:ep("brightness"),backdropContrast:ep("contrast"),backdropGrayscale:ep("grayscale"),backdropHueRotate:ep("hueRotate"),backdropInvert:ep("invert"),backdropOpacity:ep("opacity"),backdropSaturate:ep("saturate"),backdropSepia:ep("sepia"),backgroundColor:ep("colors"),backgroundImage:{none:"none"},backgroundOpacity:ep("opacity"),backgroundSize:{auto:"auto",cover:"cover",contain:"contain"},blur:{none:"none",0:"0",sm:"4px",DEFAULT:"8px",md:"12px",lg:"16px",xl:"24px","2xl":"40px","3xl":"64px"},brightness:o({},ef(200,"",100,0,50),ef(110,"",100,90,5),{75:"0.75",125:"1.25"}),borderColor:({theme:e})=>o({DEFAULT:e("colors.gray.200","currentColor")},e("colors")),borderOpacity:ep("opacity"),borderRadius:{none:"0px",sm:"0.125rem",DEFAULT:"0.25rem",md:"0.375rem",lg:"0.5rem",xl:"0.75rem","2xl":"1rem","3xl":"1.5rem","1/2":"50%",full:"9999px"},borderSpacing:ep("spacing"),borderWidth:o({DEFAULT:"1px"},ed(8,"px")),boxShadow:{sm:"0 1px 2px 0 rgba(0,0,0,0.05)",DEFAULT:"0 1px 3px 0 rgba(0,0,0,0.1), 0 1px 2px -1px rgba(0,0,0,0.1)",md:"0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1)",lg:"0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)",xl:"0 20px 25px -5px rgba(0,0,0,0.1), 0 8px 10px -6px rgba(0,0,0,0.1)","2xl":"0 25px 50px -12px rgba(0,0,0,0.25)",inner:"inset 0 2px 4px 0 rgba(0,0,0,0.05)",none:"0 0 #0000"},boxShadowColor:ep("colors"),caretColor:ep("colors"),accentColor:({theme:e})=>o({auto:"auto"},e("colors")),contrast:o({},ef(200,"",100,0,50),{75:"0.75",125:"1.25"}),content:{none:"none"},divideColor:ep("borderColor"),divideOpacity:ep("borderOpacity"),divideWidth:ep("borderWidth"),dropShadow:{sm:"0 1px 1px rgba(0,0,0,0.05)",DEFAULT:["0 1px 2px rgba(0,0,0,0.1)","0 1px 1px rgba(0,0,0,0.06)"],md:["0 4px 3px rgba(0,0,0,0.07)","0 2px 2px rgba(0,0,0,0.06)"],lg:["0 10px 8px rgba(0,0,0,0.04)","0 4px 3px rgba(0,0,0,0.1)"],xl:["0 20px 13px rgba(0,0,0,0.03)","0 8px 5px rgba(0,0,0,0.08)"],"2xl":"0 25px 25px rgba(0,0,0,0.15)",none:"0 0 #0000"},fill:ep("colors"),grayscale:{DEFAULT:"100%",0:"0"},hueRotate:{0:"0deg",15:"15deg",30:"30deg",60:"60deg",90:"90deg",180:"180deg"},invert:{DEFAULT:"100%",0:"0"},flex:{1:"1 1 0%",auto:"1 1 auto",initial:"0 1 auto",none:"none"},flexBasis:({theme:e})=>o({},e("spacing"),ec(2,6),ec(12,12),{auto:"auto",full:"100%"}),flexGrow:{DEFAULT:1,0:0},flexShrink:{DEFAULT:1,0:0},fontFamily:{sans:'ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"'.split(","),serif:'ui-serif,Georgia,Cambria,"Times New Roman",Times,serif'.split(","),mono:'ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace'.split(",")},fontSize:{xs:["0.75rem","1rem"],sm:["0.875rem","1.25rem"],base:["1rem","1.5rem"],lg:["1.125rem","1.75rem"],xl:["1.25rem","1.75rem"],"2xl":["1.5rem","2rem"],"3xl":["1.875rem","2.25rem"],"4xl":["2.25rem","2.5rem"],"5xl":["3rem","1"],"6xl":["3.75rem","1"],"7xl":["4.5rem","1"],"8xl":["6rem","1"],"9xl":["8rem","1"]},fontWeight:{thin:"100",extralight:"200",light:"300",normal:"400",medium:"500",semibold:"600",bold:"700",extrabold:"800",black:"900"},gap:ep("spacing"),gradientColorStops:ep("colors"),gridAutoColumns:{auto:"auto",min:"min-content",max:"max-content",fr:"minmax(0,1fr)"},gridAutoRows:{auto:"auto",min:"min-content",max:"max-content",fr:"minmax(0,1fr)"},gridColumn:{auto:"auto","span-full":"1 / -1"},gridRow:{auto:"auto","span-full":"1 / -1"},gridTemplateColumns:{none:"none"},gridTemplateRows:{none:"none"},height:({theme:e})=>o({},e("spacing"),ec(2,6),{min:"min-content",max:"max-content",fit:"fit-content",auto:"auto",full:"100%",screen:"100vh"}),inset:({theme:e})=>o({},e("spacing"),ec(2,4),{auto:"auto",full:"100%"}),keyframes:{spin:{from:{transform:"rotate(0deg)"},to:{transform:"rotate(360deg)"}},ping:{"0%":{transform:"scale(1)",opacity:"1"},"75%,100%":{transform:"scale(2)",opacity:"0"}},pulse:{"0%,100%":{opacity:"1"},"50%":{opacity:".5"}},bounce:{"0%, 100%":{transform:"translateY(-25%)",animationTimingFunction:"cubic-bezier(0.8,0,1,1)"},"50%":{transform:"none",animationTimingFunction:"cubic-bezier(0,0,0.2,1)"}}},letterSpacing:{tighter:"-0.05em",tight:"-0.025em",normal:"0em",wide:"0.025em",wider:"0.05em",widest:"0.1em"},lineHeight:o({},ef(10,"rem",4,3),{none:"1",tight:"1.25",snug:"1.375",normal:"1.5",relaxed:"1.625",loose:"2"}),margin:({theme:e})=>o({auto:"auto"},e("spacing")),maxHeight:({theme:e})=>o({full:"100%",min:"min-content",max:"max-content",fit:"fit-content",screen:"100vh"},e("spacing")),maxWidth:({theme:e,breakpoints:t})=>o({},t(e("screens")),{none:"none",0:"0rem",xs:"20rem",sm:"24rem",md:"28rem",lg:"32rem",xl:"36rem","2xl":"42rem","3xl":"48rem","4xl":"56rem","5xl":"64rem","6xl":"72rem","7xl":"80rem",full:"100%",min:"min-content",max:"max-content",fit:"fit-content",prose:"65ch"}),minHeight:{0:"0px",full:"100%",min:"min-content",max:"max-content",fit:"fit-content",screen:"100vh"},minWidth:{0:"0px",full:"100%",min:"min-content",max:"max-content",fit:"fit-content"},opacity:o({},ef(100,"",100,0,10),{5:"0.05",25:"0.25",75:"0.75",95:"0.95"}),order:{first:"-9999",last:"9999",none:"0"},padding:ep("spacing"),placeholderColor:ep("colors"),placeholderOpacity:ep("opacity"),outlineColor:ep("colors"),outlineOffset:ed(8,"px"),outlineWidth:ed(8,"px"),ringColor:({theme:e})=>o({},e("colors"),{DEFAULT:e("colors.blue.500","#3b82f6")}),ringOffsetColor:ep("colors"),ringOffsetWidth:ed(8,"px"),ringOpacity:({theme:e})=>o({},e("opacity"),{DEFAULT:"0.5"}),ringWidth:o({DEFAULT:"3px"},ed(8,"px")),rotate:o({},ed(2,"deg"),ed(12,"deg",3),ed(180,"deg",45)),saturate:ef(200,"",100,0,50),scale:o({},ef(150,"",100,0,50),ef(110,"",100,90,5),{75:"0.75",125:"1.25"}),scrollMargin:ep("spacing"),scrollPadding:ep("spacing"),sepia:{0:"0",DEFAULT:"100%"},skew:o({},ed(2,"deg"),ed(12,"deg",3)),space:ep("spacing"),stroke:ep("colors"),strokeWidth:ef(2),textColor:ep("colors"),textDecorationColor:ep("colors"),textDecorationThickness:o({"from-font":"from-font",auto:"auto"},ed(8,"px")),textUnderlineOffset:o({auto:"auto"},ed(8,"px")),textIndent:ep("spacing"),textOpacity:ep("opacity"),transitionDuration:({theme:e})=>o({},e("durations"),{DEFAULT:"150ms"}),transitionDelay:ep("durations"),transitionProperty:{none:"none",all:"all",DEFAULT:"color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter",colors:"color,background-color,border-color,text-decoration-color,fill,stroke",opacity:"opacity",shadow:"box-shadow",transform:"transform"},transitionTimingFunction:{DEFAULT:"cubic-bezier(0.4,0,0.2,1)",linear:"linear",in:"cubic-bezier(0.4,0,1,1)",out:"cubic-bezier(0,0,0.2,1)","in-out":"cubic-bezier(0.4,0,0.2,1)"},translate:({theme:e})=>o({},e("spacing"),ec(2,4),{full:"100%"}),width:({theme:e})=>o({min:"min-content",max:"max-content",fit:"fit-content",screen:"100vw"},e("flexBasis")),willChange:{scroll:"scroll-position"},zIndex:o({},ef(50,"",1,0,10),{auto:"auto"})};function ec(e,t){let r={};do for(var o=1;ot(e)}let eu={"*,::before,::after":{boxSizing:"border-box",borderWidth:"0",borderStyle:"solid",borderColor:"theme(borderColor.DEFAULT, currentColor)"},"::before,::after":{"--tw-content":"''"},html:{lineHeight:1.5,WebkitTextSizeAdjust:"100%",MozTabSize:"4",tabSize:4,fontFamily:`theme(fontFamily.sans, ${es.fontFamily.sans})`},body:{margin:"0",lineHeight:"inherit"},hr:{height:"0",color:"inherit",borderTopWidth:"1px"},"abbr:where([title])":{textDecoration:"underline dotted"},"h1,h2,h3,h4,h5,h6":{fontSize:"inherit",fontWeight:"inherit"},a:{color:"inherit",textDecoration:"inherit"},"b,strong":{fontWeight:"bolder"},"code,kbd,samp,pre":{fontFamily:`theme(fontFamily.mono, ${es.fontFamily.mono})`,fontSize:"1em"},small:{fontSize:"80%"},"sub,sup":{fontSize:"75%",lineHeight:0,position:"relative",verticalAlign:"baseline"},sub:{bottom:"-0.25em"},sup:{top:"-0.5em"},table:{textIndent:"0",borderColor:"inherit",borderCollapse:"collapse"},"button,input,optgroup,select,textarea":{fontFamily:"inherit",fontSize:"100%",lineHeight:"inherit",color:"inherit",margin:"0",padding:"0"},"button,select":{textTransform:"none"},"button,[type='button'],[type='reset'],[type='submit']":{WebkitAppearance:"button",backgroundColor:"transparent",backgroundImage:"none"},":-moz-focusring":{outline:"auto"},":-moz-ui-invalid":{boxShadow:"none"},progress:{verticalAlign:"baseline"},"::-webkit-inner-spin-button,::-webkit-outer-spin-button":{height:"auto"},"[type='search']":{WebkitAppearance:"textfield",outlineOffset:"-2px"},"::-webkit-search-decoration":{WebkitAppearance:"none"},"::-webkit-file-upload-button":{WebkitAppearance:"button",font:"inherit"},summary:{display:"list-item"},"blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre":{margin:"0"},fieldset:{margin:"0",padding:"0"},legend:{padding:"0"},"ol,ul,menu":{listStyle:"none",margin:"0",padding:"0"},textarea:{resize:"vertical"},"input::placeholder,textarea::placeholder":{opacity:1,color:"theme(colors.gray.400, #9ca3af)"},'button,[role="button"]':{cursor:"pointer"},":disabled":{cursor:"default"},"img,svg,video,canvas,audio,iframe,embed,object":{display:"block",verticalAlign:"middle"},"img,video":{maxWidth:"100%",height:"auto"},"[hidden]":{display:"none"}},eg=[L("\\[([-\\w]+):(.+)]",({1:e,2:t},r)=>({"@layer overrides":{"&":{[e]:_(`[${t}]`,e,r)}}})),L("(group|peer)(~[^-[]+)?",({input:e},{h:t})=>[{c:t(e)}]),I("aspect-","aspectRatio"),L("container",(e,{theme:t})=>{let{screens:r=t("screens"),center:n,padding:i}=t("container"),a=o({width:"100%",marginRight:n&&"auto",marginLeft:n&&"auto"},d("xs"));for(let l in r){let c=r[l];"string"==typeof c&&(a[s(c)]={"&":o({maxWidth:c},d(l))})}return a;function d(e){let t=i&&("string"==typeof i?i:i[e]||i.DEFAULT);if(t)return{paddingRight:t,paddingLeft:t}}}),I("content-","content",({_:e})=>({"--tw-content":e,content:"var(--tw-content)"})),L("(?:box-)?decoration-(slice|clone)","boxDecorationBreak"),L("box-(border|content)","boxSizing",({1:e})=>e+"-box"),L("hidden",{display:"none"}),L("table-(auto|fixed)","tableLayout"),L(["(block|flex|table|grid|inline|contents|flow-root|list-item)","(inline-(block|flex|table|grid))","(table-(caption|cell|column|row|(column|row|footer|header)-group))"],"display"),"(float)-(left|right|none)","(clear)-(left|right|none|both)","(overflow(?:-[xy])?)-(auto|hidden|clip|visible|scroll)","(isolation)-(auto)",L("isolate","isolation"),L("object-(contain|cover|fill|none|scale-down)","objectFit"),I("object-","objectPosition"),L("object-(top|bottom|center|(left|right)(-(top|bottom))?)","objectPosition",em),L("overscroll(-[xy])?-(auto|contain|none)",({1:e="",2:t})=>({["overscroll-behavior"+e]:t})),L("(static|fixed|absolute|relative|sticky)","position"),I("-?inset(-[xy])?(?:$|-)","inset",({1:e,_:t})=>({top:"-x"!=e&&t,right:"-y"!=e&&t,bottom:"-x"!=e&&t,left:"-y"!=e&&t})),I("-?(top|bottom|left|right)(?:$|-)","inset"),L("visible","visibility"),L("invisible",{visibility:"hidden"}),I("-?z-","zIndex"),L("flex-((row|col)(-reverse)?)","flexDirection",eb),L("flex-(wrap|wrap-reverse|nowrap)","flexWrap"),I("(flex-(?:grow|shrink))(?:$|-)"),I("(flex)-"),I("grow(?:$|-)","flexGrow"),I("shrink(?:$|-)","flexShrink"),I("basis-","flexBasis"),I("-?(order)-"),"-?(order)-(\\d+)",I("grid-cols-","gridTemplateColumns"),L("grid-cols-(\\d+)","gridTemplateColumns",eA),I("col-","gridColumn"),L("col-(span)-(\\d+)","gridColumn",eC),I("col-start-","gridColumnStart"),L("col-start-(auto|\\d+)","gridColumnStart"),I("col-end-","gridColumnEnd"),L("col-end-(auto|\\d+)","gridColumnEnd"),I("grid-rows-","gridTemplateRows"),L("grid-rows-(\\d+)","gridTemplateRows",eA),I("row-","gridRow"),L("row-(span)-(\\d+)","gridRow",eC),I("row-start-","gridRowStart"),L("row-start-(auto|\\d+)","gridRowStart"),I("row-end-","gridRowEnd"),L("row-end-(auto|\\d+)","gridRowEnd"),L("grid-flow-((row|col)(-dense)?)","gridAutoFlow",e=>em(eb(e))),L("grid-flow-(dense)","gridAutoFlow"),I("auto-cols-","gridAutoColumns"),I("auto-rows-","gridAutoRows"),I("gap-x(?:$|-)","gap","columnGap"),I("gap-y(?:$|-)","gap","rowGap"),I("gap(?:$|-)","gap"),"(justify-(?:items|self))-",L("justify-","justifyContent",ew),L("(content|items|self)-",e=>({["align-"+e[1]]:ew(e)})),L("(place-(content|items|self))-",({1:e,$$:t})=>({[e]:("wun".includes(t[3])?"space-":"")+t})),I("p([xytrbl])?(?:$|-)","padding",ey("padding")),I("-?m([xytrbl])?(?:$|-)","margin",ey("margin")),I("-?space-(x|y)(?:$|-)","space",({1:e,_:t})=>({"&>:not([hidden])~:not([hidden])":{[`--tw-space-${e}-reverse`]:"0",["margin-"+({y:"top",x:"left"})[e]]:`calc(${t} * calc(1 - var(--tw-space-${e}-reverse)))`,["margin-"+({y:"bottom",x:"right"})[e]]:`calc(${t} * var(--tw-space-${e}-reverse))`}})),L("space-(x|y)-reverse",({1:e})=>({"&>:not([hidden])~:not([hidden])":{[`--tw-space-${e}-reverse`]:"1"}})),I("w-","width"),I("min-w-","minWidth"),I("max-w-","maxWidth"),I("h-","height"),I("min-h-","minHeight"),I("max-h-","maxHeight"),I("font-","fontWeight"),I("font-","fontFamily","fontFamily",ex),L("antialiased",{WebkitFontSmoothing:"antialiased",MozOsxFontSmoothing:"grayscale"}),L("subpixel-antialiased",{WebkitFontSmoothing:"auto",MozOsxFontSmoothing:"auto"}),L("italic","fontStyle"),L("not-italic",{fontStyle:"normal"}),L("(ordinal|slashed-zero|(normal|lining|oldstyle|proportional|tabular)-nums|(diagonal|stacked)-fractions)",({1:e,2:t="",3:r})=>"normal"==t?{fontVariantNumeric:"normal"}:{["--tw-"+(r?"numeric-fraction":"pt".includes(t[0])?"numeric-spacing":t?"numeric-figure":e)]:e,fontVariantNumeric:"var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)","@layer defaults":{"*,::before,::after,::backdrop":{"--tw-ordinal":"var(--tw-empty,/*!*/ /*!*/)","--tw-slashed-zero":"var(--tw-empty,/*!*/ /*!*/)","--tw-numeric-figure":"var(--tw-empty,/*!*/ /*!*/)","--tw-numeric-spacing":"var(--tw-empty,/*!*/ /*!*/)","--tw-numeric-fraction":"var(--tw-empty,/*!*/ /*!*/)"}}}),I("tracking-","letterSpacing"),I("leading-","lineHeight"),L("list-(inside|outside)","listStylePosition"),I("list-","listStyleType"),L("list-","listStyleType"),I("placeholder-opacity-","placeholderOpacity",({_:e})=>({"&::placeholder":{"--tw-placeholder-opacity":e}})),N("placeholder-",{property:"color",selector:"&::placeholder"}),L("text-(left|center|right|justify|start|end)","textAlign"),L("text-(ellipsis|clip)","textOverflow"),I("text-opacity-","textOpacity","--tw-text-opacity"),N("text-",{property:"color"}),I("text-","fontSize",({_:e})=>"string"==typeof e?{fontSize:e}:o({fontSize:e[0]},"string"==typeof e[1]?{lineHeight:e[1]}:e[1])),I("indent-","textIndent"),L("(overline|underline|line-through)","textDecorationLine"),L("no-underline",{textDecorationLine:"none"}),I("underline-offset-","textUnderlineOffset"),N("decoration-",{section:"textDecorationColor",opacityVariable:!1,opacitySection:"opacity"}),I("decoration-","textDecorationThickness"),L("decoration-","textDecorationStyle"),L("(uppercase|lowercase|capitalize)","textTransform"),L("normal-case",{textTransform:"none"}),L("truncate",{overflow:"hidden",whiteSpace:"nowrap",textOverflow:"ellipsis"}),L("align-","verticalAlign"),L("whitespace-","whiteSpace"),L("break-normal",{wordBreak:"normal",overflowWrap:"normal"}),L("break-words",{overflowWrap:"break-word"}),L("break-all",{wordBreak:"break-all"}),N("caret-",{opacityVariable:!1,opacitySection:"opacity"}),N("accent-",{opacityVariable:!1,opacitySection:"opacity"}),L("bg-gradient-to-([trbl]|[tb][rl])","backgroundImage",({1:e})=>`linear-gradient(to ${eh(e," ")},var(--tw-gradient-stops))`),N("from-",{section:"gradientColorStops",opacityVariable:!1,opacitySection:"opacity"},({_:e})=>({"--tw-gradient-from":e.value,"--tw-gradient-to":e.color({opacityValue:"0"}),"--tw-gradient-stops":"var(--tw-gradient-from),var(--tw-gradient-to)"})),N("via-",{section:"gradientColorStops",opacityVariable:!1,opacitySection:"opacity"},({_:e})=>({"--tw-gradient-to":e.color({opacityValue:"0"}),"--tw-gradient-stops":`var(--tw-gradient-from),${e.value},var(--tw-gradient-to)`})),N("to-",{section:"gradientColorStops",property:"--tw-gradient-to",opacityVariable:!1,opacitySection:"opacity"}),L("bg-(fixed|local|scroll)","backgroundAttachment"),L("bg-origin-(border|padding|content)","backgroundOrigin",({1:e})=>e+"-box"),L(["bg-(no-repeat|repeat(-[xy])?)","bg-repeat-(round|space)"],"backgroundRepeat"),L("bg-blend-","backgroundBlendMode"),L("bg-clip-(border|padding|content|text)","backgroundClip",({1:e})=>e+("text"==e?"":"-box")),I("bg-opacity-","backgroundOpacity","--tw-bg-opacity"),N("bg-",{section:"backgroundColor"}),I("bg-","backgroundImage"),I("bg-","backgroundPosition"),L("bg-(top|bottom|center|(left|right)(-(top|bottom))?)","backgroundPosition",em),I("bg-","backgroundSize"),I("rounded(?:$|-)","borderRadius"),I("rounded-([trbl]|[tb][rl])(?:$|-)","borderRadius",({1:e,_:t})=>{let r={t:["tl","tr"],r:["tr","br"],b:["bl","br"],l:["bl","tl"]}[e]||[e,e];return{[`border-${eh(r[0])}-radius`]:t,[`border-${eh(r[1])}-radius`]:t}}),L("border-(collapse|separate)","borderCollapse"),I("border-opacity(?:$|-)","borderOpacity","--tw-border-opacity"),L("border-(solid|dashed|dotted|double|none)","borderStyle"),I("border-spacing(-[xy])?(?:$|-)","borderSpacing",({1:e,_:t})=>({"@layer defaults":{"*,::before,::after,::backdrop":{"--tw-border-spacing-x":0,"--tw-border-spacing-y":0}},["--tw-border-spacing"+(e||"-x")]:t,["--tw-border-spacing"+(e||"-y")]:t,"border-spacing":"var(--tw-border-spacing-x) var(--tw-border-spacing-y)"})),N("border-([xytrbl])-",{section:"borderColor"},ey("border","Color")),N("border-"),I("border-([xytrbl])(?:$|-)","borderWidth",ey("border","Width")),I("border(?:$|-)","borderWidth"),I("divide-opacity(?:$|-)","divideOpacity",({_:e})=>({"&>:not([hidden])~:not([hidden])":{"--tw-divide-opacity":e}})),L("divide-(solid|dashed|dotted|double|none)",({1:e})=>({"&>:not([hidden])~:not([hidden])":{borderStyle:e}})),L("divide-([xy]-reverse)",({1:e})=>({"&>:not([hidden])~:not([hidden])":{["--tw-divide-"+e]:"1"}})),I("divide-([xy])(?:$|-)","divideWidth",({1:e,_:t})=>{let r={x:"lr",y:"tb"}[e];return{"&>:not([hidden])~:not([hidden])":{[`--tw-divide-${e}-reverse`]:"0",[`border-${eh(r[0])}Width`]:`calc(${t} * calc(1 - var(--tw-divide-${e}-reverse)))`,[`border-${eh(r[1])}Width`]:`calc(${t} * var(--tw-divide-${e}-reverse))`}}}),N("divide-",{property:"borderColor",selector:"&>:not([hidden])~:not([hidden])"}),I("ring-opacity(?:$|-)","ringOpacity","--tw-ring-opacity"),N("ring-offset-",{property:"--tw-ring-offset-color",opacityVariable:!1}),I("ring-offset(?:$|-)","ringOffsetWidth","--tw-ring-offset-width"),L("ring-inset",{"--tw-ring-inset":"inset"}),N("ring-",{property:"--tw-ring-color"}),I("ring(?:$|-)","ringWidth",({_:e},{theme:t})=>({"--tw-ring-offset-shadow":"var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)","--tw-ring-shadow":`var(--tw-ring-inset) 0 0 0 calc(${e} + var(--tw-ring-offset-width)) var(--tw-ring-color)`,boxShadow:"var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)","@layer defaults":{"*,::before,::after,::backdrop":{"--tw-ring-offset-shadow":"0 0 #0000","--tw-ring-shadow":"0 0 #0000","--tw-shadow":"0 0 #0000","--tw-shadow-colored":"0 0 #0000","&":{"--tw-ring-inset":"var(--tw-empty,/*!*/ /*!*/)","--tw-ring-offset-width":t("ringOffsetWidth","","0px"),"--tw-ring-offset-color":z(t("ringOffsetColor","","#fff")),"--tw-ring-color":z(t("ringColor","","#93c5fd"),{opacityVariable:"--tw-ring-opacity"}),"--tw-ring-opacity":t("ringOpacity","","0.5")}}}})),N("shadow-",{section:"boxShadowColor",opacityVariable:!1,opacitySection:"opacity"},({_:e})=>({"--tw-shadow-color":e.value,"--tw-shadow":"var(--tw-shadow-colored)"})),I("shadow(?:$|-)","boxShadow",({_:e})=>({"--tw-shadow":ex(e),"--tw-shadow-colored":ex(e).replace(/([^,]\s+)(?:#[a-f\d]+|(?:(?:hsl|rgb)a?|hwb|lab|lch|color|var)\(.+?\)|[a-z]+)(,|$)/g,"$1var(--tw-shadow-color)$2"),boxShadow:"var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)","@layer defaults":{"*,::before,::after,::backdrop":{"--tw-ring-offset-shadow":"0 0 #0000","--tw-ring-shadow":"0 0 #0000","--tw-shadow":"0 0 #0000","--tw-shadow-colored":"0 0 #0000"}}})),I("(opacity)-"),L("mix-blend-","mixBlendMode"),...ev(),...ev("backdrop-"),I("transition(?:$|-)","transitionProperty",(e,{theme:t})=>({transitionProperty:ex(e),transitionTimingFunction:"none"==e._?void 0:ex(t("transitionTimingFunction","")),transitionDuration:"none"==e._?void 0:ex(t("transitionDuration",""))})),I("duration(?:$|-)","transitionDuration","transitionDuration",ex),I("ease(?:$|-)","transitionTimingFunction","transitionTimingFunction",ex),I("delay(?:$|-)","transitionDelay","transitionDelay",ex),I("animate(?:$|-)","animation",(e,{theme:t,h:r})=>{let o=ex(e),n=o.split(" "),i=t("keyframes",n[0]);return i?{["@keyframes "+(n[0]=r(n[0]))]:i,animation:n.join(" ")}:{animation:o}}),"(transform)-(none)",L("transform",e$),L("transform-(cpu|gpu)",({1:e})=>({"--tw-transform":eS("gpu"==e)})),I("scale(-[xy])?-","scale",({1:e,_:t})=>o({["--tw-scale"+(e||"-x")]:t,["--tw-scale"+(e||"-y")]:t},e$())),I("-?(rotate)-","rotate",ek),I("-?(translate-[xy])-","translate",ek),I("-?(skew-[xy])-","skew",ek),L("origin-(center|((top|bottom)(-(left|right))?)|left|right)","transformOrigin",em),"(appearance)-",I("(columns)-"),"(columns)-(\\d+)","(break-(?:before|after|inside))-",I("(cursor)-"),"(cursor)-",L("snap-(none)","scroll-snap-type"),L("snap-(x|y|both)",({1:e})=>({"scroll-snap-type":e+" var(--tw-scroll-snap-strictness)","@layer defaults":{"*,::before,::after,::backdrop":{"--tw-scroll-snap-strictness":"proximity"}}})),L("snap-(mandatory|proximity)","--tw-scroll-snap-strictness"),L("snap-(?:(start|end|center)|align-(none))","scroll-snap-align"),L("snap-(normal|always)","scroll-snap-stop"),L("scroll-(auto|smooth)","scroll-behavior"),I("scroll-p([xytrbl])?(?:$|-)","padding",ey("scroll-padding")),I("-?scroll-m([xytrbl])?(?:$|-)","scroll-margin",ey("scroll-margin")),L("touch-(auto|none|manipulation)","touch-action"),L("touch-(pinch-zoom|pan-(?:(x|left|right)|(y|up|down)))",({1:e,2:t,3:r})=>({[`--tw-${t?"pan-x":r?"pan-y":e}`]:e,"touch-action":"var(--tw-touch-action)","@layer defaults":{"*,::before,::after,::backdrop":{"--tw-pan-x":"var(--tw-empty,/*!*/ /*!*/)","--tw-pan-y":"var(--tw-empty,/*!*/ /*!*/)","--tw-pinch-zoom":"var(--tw-empty,/*!*/ /*!*/)","--tw-touch-action":"var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom)"}}})),L("outline-none",{outline:"2px solid transparent","outline-offset":"2px"}),L("outline",{outlineStyle:"solid"}),L("outline-(dashed|dotted|double|hidden)","outlineStyle"),I("(outline-offset)-"),N("outline-",{opacityVariable:!1,opacitySection:"opacity"}),I("outline-","outlineWidth"),"(pointer-events)-",I("(will-change)-"),"(will-change)-",["resize(?:-(none|x|y))?","resize",({1:e})=>({x:"horizontal",y:"vertical"})[e]||e||"both"],L("select-(none|text|all|auto)","userSelect"),N("fill-",{section:"fill",opacityVariable:!1,opacitySection:"opacity"}),N("stroke-",{section:"stroke",opacityVariable:!1,opacitySection:"opacity"}),I("stroke-","strokeWidth"),L("sr-only",{position:"absolute",width:"1px",height:"1px",padding:"0",margin:"-1px",overflow:"hidden",whiteSpace:"nowrap",clip:"rect(0,0,0,0)",borderWidth:"0"}),L("not-sr-only",{position:"static",width:"auto",height:"auto",padding:"0",margin:"0",overflow:"visible",whiteSpace:"normal",clip:"auto"})];function em(e){return("string"==typeof e?e:e[1]).replace(/-/g," ").trim()}function eb(e){return("string"==typeof e?e:e[1]).replace("col","column")}function eh(e,t="-"){let r=[];for(let o of e)r.push({t:"top",r:"right",b:"bottom",l:"left"}[o]);return r.join(t)}function ex(e){return e&&""+(e._||e)}function ew({$$:e}){return(({r:"flex-","":"flex-",w:"space-",u:"space-",n:"space-"})[e[3]||""]||"")+e}function ey(e,t=""){return({1:r,_:n})=>{let i={x:"lr",y:"tb"}[r]||r+r;return i?o({},B(e+"-"+eh(i[0])+t,n),B(e+"-"+eh(i[1])+t,n)):B(e+t,n)}}function ev(e=""){let t=["blur","brightness","contrast","grayscale","hue-rotate","invert",e&&"opacity","saturate","sepia",!e&&"drop-shadow"].filter(Boolean),r={};for(let n of t)r[`--tw-${e}${n}`]="var(--tw-empty,/*!*/ /*!*/)";return r={[`${e}filter`]:t.map(t=>`var(--tw-${e}${t})`).join(" "),"@layer defaults":{"*,::before,::after,::backdrop":r}},[`(${e}filter)-(none)`,L(`${e}filter`,r),...t.map(t=>I(`${"h"==t[0]?"-?":""}(${e}${t})(?:$|-)`,t,({1:e,_:n})=>o({[`--tw-${e}`]:c(n).map(e=>`${t}(${e})`).join(" ")},r)))]}function ek({1:e,_:t}){return o({["--tw-"+e]:t},e$())}function e$(){return{transform:"var(--tw-transform)","@layer defaults":{"*,::before,::after,::backdrop":{"--tw-translate-x":"0","--tw-translate-y":"0","--tw-rotate":"0","--tw-skew-x":"0","--tw-skew-y":"0","--tw-scale-x":"1","--tw-scale-y":"1","--tw-transform":eS()}}}}function eS(e){return[e?"translate3d(var(--tw-translate-x),var(--tw-translate-y),0)":"translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y))","rotate(var(--tw-rotate))","skewX(var(--tw-skew-x))","skewY(var(--tw-skew-y))","scaleX(var(--tw-scale-x))","scaleY(var(--tw-scale-y))"].join(" ")}function eC({1:e,2:t}){return`${e} ${t} / ${e} ${t}`}function eA({1:e}){return`repeat(${e},minmax(0,1fr))`}let ez=[["sticky","@supports ((position: -webkit-sticky) or (position:sticky))"],["motion-reduce","@media (prefers-reduced-motion:reduce)"],["motion-safe","@media (prefers-reduced-motion:no-preference)"],["print","@media print"],["portrait","@media (orientation:portrait)"],["landscape","@media (orientation:landscape)"],["contrast-more","@media (prefers-contrast:more)"],["contrast-less","@media (prefers-contrast:less)"],["marker","& *::marker,&::marker"],["selection","& *::selection,&::selection"],["first-letter","&::first-letter"],["first-line","&::first-line"],["file","&::file-selector-button"],["placeholder","&::placeholder"],["backdrop","&::backdrop"],["first","&:first-child"],["last","&:last-child"],["even","&:nth-child(2n)"],["odd","&:nth-child(odd)"],["open","&[open]"],["((group|peer)(~[^-[]+)?)(-[a-z-]+|-\\[(.+)]|\\[.+])",({1:e,4:t,5:r},{e:o,h:n,v:i})=>{let a=r&&H(r)||("["==t[0]?t:i(t.slice(1)));return`${(a.includes("&")?a:"&"+a).replace(/&/g,`:merge(.${o(n(e))})`)}${"p"==e[0]?"~":" "}&`}],["(ltr|rtl)",({1:e})=>`[dir="${e}"] &`],[/^\[(.+)]$/,({1:e})=>/[&@]/.test(e)&&H(e).replace(/[}]+$/,"").split("{")]],eO=function(e){if(document.currentScript){let t=()=>r.disconnect(),r=new MutationObserver(r=>{for(let{target:o}of r)if(o===document.body)return e(),t()});return r.observe(document.documentElement,{childList:!0,subtree:!0}),t}return f}(ej);function ej(e={},r){var{disablePreflight:i}=e,s=n(e,["disablePreflight"]);return eO(),function(e,r=!0){var i;let s=q(e);return function(e={},r=er,i){return null==t||t.destroy(),t=function(e=en,t=document.documentElement){if(!t)return e;let r=new MutationObserver(n);r.observe(t,{attributeFilter:["class"],subtree:!0,childList:!0}),i(t),n([{target:t,type:""}]);let{destroy:o}=e;return e.destroy=()=>{r.disconnect(),o.call(e)},e;function n(e){for(let{type:t,target:o}of e)if("a"==t[0])i(o);else for(let n of o.querySelectorAll("[class]"))i(n);r.takeRecords()}function i(t){var r,o;let n;let i=t.getAttribute("class");i&&(r=i)!=(o=n=e(i))&&""+r.split(" ").sort()!=""+o.split(" ").sort()&&t.setAttribute("class",n)}}(function(e,t){let r=q(e),i=function({theme:e,darkMode:t,darkColor:r,variants:o,rules:i,hash:s,stringify:f,ignorelist:p}){let u=new Map,g=new Map,m=new Map,b=new Map,h=K(p,(e,t)=>t.test(e));o.push(["dark",Array.isArray(t)||"class"==t?`${c(t)[1]||".dark"} &`:"string"==typeof t&&"media"!=t?t:"@media (prefers-color-scheme:dark)"]);let x="function"==typeof s?e=>s(e,l):s?l:d;return{theme:function(e){var{extend:t={}}=e,r=n(e,["extend"]);let o={},i={get colors(){return a("colors")},theme:a,negative:()=>({}),breakpoints(e){let t={};for(let r in e)"string"==typeof e[r]&&(t["screen-"+r]=e[r]);return t}};return a;function a(e,n,i,s){if(e){var c;if({1:e,2:s}=/^(\S+?)(?:\s*\/\s*([^/]+))?$/.exec(e)||[,e],/[.[]/.test(e)){let d=[];e.replace(/\[([^\]]+)\]|([^.[]+)/g,(e,t,r=t)=>d.push(r)),e=d.shift(),i=n,n=d.join("-")}let f=o[e]||Object.assign(Object.assign(o[e]={},l(r,e)),l(t,e));if(null==n)return f;let p=null!=(c=f[n||"DEFAULT"])?c:i;return s?z(p,{opacityValue:j(s,a)}):p}let u={};for(let g of[...Object.keys(r),...Object.keys(t)])u[g]=a(g);return u}function l(e,t){let r=e[t];return("function"==typeof r&&(r=r(i)),r&&/color|fill|stroke/i.test(t))?function e(t,r=[]){let o={};for(let n in t){let i=t[n],a=[...r,n];o[a.join("-")]=i,"DEFAULT"==n&&(a=r,o[r.join("-")]=i),"object"==typeof i&&Object.assign(o,e(i,a))}return o}(r):r}}(e),e:a,h:x,s(e,t){return f(ee(e,x),ee(t,x),this)},d(e,t,o){return null==r?void 0:r(e,t,this,o)},v(e){return u.has(e)||u.set(e,Y(e,o,g,J,this)||"&:"+e),u.get(e)},r(e,t){let r=JSON.stringify([e,t]);return m.has(r)||m.set(r,!h(e,this)&&Y(e,i,b,X,this,t)),m.get(r)}}}(r),s=new Map,f=[],u=new Set;function g(e){let r=e.n&&i.h(e.n),n=x(r?o({},e,{n:r}):e);if(n&&!u.has(n)){u.add(n);let a=k(f,e);t.insert(n,a,e),f.splice(a,0,e)}return r}return t.resume(e=>s.set(e,e),(e,r)=>{t.insert(e,f.length,r),f.push(r),u.add(e)}),Object.defineProperties(function(e){if(!s.size)for(let t of c(r.preflight))"function"==typeof t&&(t=t(i)),t&&("string"==typeof t?W("",p.b,M(t),i,p.b,[],!1,!0):O(t,{},i,p.b)).forEach(g);e=""+e;let o=s.get(e);if(!o){let n=new Set;for(let a of F(M(e),i))n.add(a.c).add(g(a));o=[...n].filter(Boolean).join(" "),s.set(e,o).set(o,o)}return o},Object.getOwnPropertyDescriptors({get target(){return t.target},theme:i.theme,config:r,snapshot(){let e=t.snapshot(),r=new Set(u),o=new Map(s),n=[...f];return()=>{e(),u=r,s=o,f=n}},clear(){t.clear(),u=new Set,s=new Map,f=[]},destroy(){this.clear(),t.destroy()}}))}(e,"function"==typeof r?r():r),void 0)}(o({},s,{hash:null!=(i=s.hash)?i:r}),()=>er(!r))}(q(o({},s,{presets:[({stringify:e})=>({stringify(t,r,o){var n,i;let a="",l=ei.get(t);l&&(a+=e(l,r,o)+";");let s=(n=/^(?:(text-(?:decoration$|e|or|si)|back(?:ground-cl|d|f)|box-d|mask(?:$|-[ispro]|-cl)|pr|hyphena|flex-d)|(tab-|column(?!-s)|text-align-l)|(ap)|u|hy)/i.exec(t))?n[1]?1:n[2]?2:n[3]?3:5:0,c=(i=/^(?:(pos)|(cli)|(background-i)|(flex(?:$|-b)|(?:max-|min-)?(?:block-s|inl|he|widt))|dis)/i.exec(t))?i[1]?/^sti/i.test(r)?1:0:i[2]?/^pat/i.test(r)?1:0:i[3]?/^image-/i.test(r)?1:0:i[4]?"-"===r[3]?2:0:/^(?:inline-)?grid$/i.test(r)?4:0:0;for(let d of ea)s&d[1]&&(a+=e(d[0]+t,r,o)+";"),c&d[1]&&(a+=e(t,d[0]+r,o)+";");return a+e(t,r,o)}}),function({disablePreflight:e}={}){return{preflight:e?void 0:eu,theme:es,variants:ez,rules:eg}}({disablePreflight:i}),...c(s.presets)]})),r)}return e.install=ej,e.presetTailwind_colors=el,e.presetTailwind_defaultTheme=es,e}({});//# sourceMappingURL=cdn.global.js.map