diff --git a/developerID_installer.cer b/developerID_installer.cer new file mode 100644 index 0000000..fc77fcf Binary files /dev/null and b/developerID_installer.cer differ diff --git a/electron-builder.yml b/electron-builder.yml index 3108d7d..3f6ab91 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -25,6 +25,7 @@ mac: - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. notarize: false + cscLink: https://drive.google.com/uc?export=download&id=1gd3i3xEhJoh8xfVH52v_0ocKz8IvdI4B dmg: artifactName: ${name}-${version}.${ext} linux: diff --git a/out/main/index.js b/out/main/index.js index 5010bd2..ea0a567 100644 --- a/out/main/index.js +++ b/out/main/index.js @@ -1,9 +1,9 @@ "use strict"; const utils = require("@electron-toolkit/utils"); const electron = require("electron"); -const path = require("path"); +const filesystemPlugin = require("takerofnotes-plugin-filesystem"); const fs = require("fs/promises"); -const matter = require("gray-matter"); +const path = require("path"); const flexsearch = require("flexsearch"); const crypto = require("crypto"); class PluginRegistry { @@ -23,96 +23,28 @@ class PluginRegistry { return Array.from(this.plugins.values()); } } -class BaseNotesAdapter { - constructor(config = {}) { - this.config = config; - } - async init() { - throw new Error("init() not implemented"); - } - async getAll() { - throw new Error("getAll() not implemented"); - } - async create(note) { - throw new Error("create() not implemented"); - } - async update(note) { - throw new Error("update() not implemented"); - } - async delete(id) { - throw new Error("delete() not implemented"); - } -} -class FileSystemNotesAdapter extends BaseNotesAdapter { - constructor(config) { - super(); - for (const field in config) { - this[field] = config[field]; - } - } - async init() { - await fs.mkdir(this.notesDir, { recursive: true }); - } - async getAll() { - const files = await fs.readdir(this.notesDir); - const notes = []; - for (const file of files) { - if (!file.endsWith(".md")) continue; - const fullPath = path.join(this.notesDir, file); - const raw = await fs.readFile(fullPath, "utf8"); - const parsed = matter(raw); - notes.push({ - ...parsed.data, - content: parsed.content - }); - } - return notes; - } - async create(note) { - await this._write(note); - } - async update(note) { - await this._write(note); - } - async delete(id) { - const filePath = path.join(this.notesDir, `${id}.md`); - await fs.unlink(filePath); - } - async _write(note) { - const filePath = path.join(this.notesDir, `${note.id}.md`); - const fileContent = matter.stringify(note.content, { - id: note.id, - title: note.title, - category: note.category ?? null, - createdAt: note.createdAt, - updatedAt: note.updatedAt - }); - await fs.writeFile(filePath, fileContent, "utf8"); - } -} -const filesystemPlugin = { - id: "filesystem", - name: "Local Filesystem", - description: "Stores notes as markdown files locally.", - version: "1.0.0", - configSchema: [ - { - key: "notesDir", - label: "Notes Directory", - type: "directory", - default: path.join(electron.app.getPath("userData"), "notes"), - required: true - } - ], - createAdapter(config) { - return new FileSystemNotesAdapter(config); - } -}; +const USER_DATA_STRING = "__DEFAULT_USER_DATA__"; class PluginConfig { constructor(defaultPlugin) { this.defaultPlugin = defaultPlugin; this.configPath = path.join(electron.app.getPath("userData"), "config.json"); } + // Helper to replace placeholders with dynamic values, recursively + _resolveDefaults(config) { + if (Array.isArray(config)) { + return config.map((item) => this._resolveDefaults(item)); + } else if (config && typeof config === "object") { + const resolved = {}; + for (const [key, value] of Object.entries(config)) { + resolved[key] = this._resolveDefaults(value); + } + return resolved; + } else if (typeof config === "string" && config.includes(USER_DATA_STRING)) { + return config.replace(USER_DATA_STRING, electron.app.getPath("userData")); + } else { + return config; + } + } async load() { let parsed; try { @@ -131,15 +63,21 @@ class PluginConfig { adapterConfig: defaultConfig }; await this.write(parsed); + } else { + parsed.adapterConfig = this._resolveDefaults(parsed.adapterConfig); } return parsed; } async write(configObject) { const dir = path.dirname(this.configPath); await fs.mkdir(dir, { recursive: true }); + const resolvedConfig = { + ...configObject, + adapterConfig: this._resolveDefaults(configObject.adapterConfig) + }; await fs.writeFile( this.configPath, - JSON.stringify(configObject, null, 2), + JSON.stringify(resolvedConfig, null, 2), "utf8" ); } @@ -297,7 +235,7 @@ electron.app.whenReady().then(async () => { createNoteWindow(noteId); }); const registry = new PluginRegistry(); - registry.register(filesystemPlugin); + registry.register(filesystemPlugin.default); const config = await new PluginConfig(filesystemPlugin).load(); const plugin = registry.get(config.activeAdapter); const adapter = plugin.createAdapter(config.adapterConfig); diff --git a/out/renderer/assets/index-rzd5KlBx.css b/out/renderer/assets/index-CZWw79gc.css similarity index 71% rename from out/renderer/assets/index-rzd5KlBx.css rename to out/renderer/assets/index-CZWw79gc.css index da9fba7..b42ae97 100644 --- a/out/renderer/assets/index-rzd5KlBx.css +++ b/out/renderer/assets/index-CZWw79gc.css @@ -264,8 +264,8 @@ html.has-scroll-smooth .hide-on-smooth-scroll { :root { --layout-column-count: 5; - --layout-column-gap: 4.5454545455vw; - --layout-margin: 6.8181818182vw; + --layout-column-gap: 5.6497175141vw; + --layout-margin: 8.4745762712vw; --layout-width: calc(100vw - (2 * var(--layout-margin))); --layout-column-width: calc( ( @@ -278,13 +278,6 @@ html.has-scroll-smooth .hide-on-smooth-scroll { var(--layout-column-count) ); } -@media (min-width: 800px) { - :root { - --layout-column-count: 18; - --layout-column-gap: 1.1574074074vw; - --layout-margin: 3.4722222222vw; - } -} .layout-block, .layout-grid { max-width: var(--layout-width); @@ -394,8 +387,7 @@ html.lenis { :root { font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - background: var(--theme-bg); - color: var(--theme-fg); + background: var(--black); font-synthesis: none; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; @@ -417,9 +409,21 @@ h6 { font-family: var(--font-display); font-weight: 400; letter-spacing: -0.02em; - line-height: 1; + line-height: 1.3; font-size: 8.4745762712vw; } +.h1.mono, +h1.mono, +h2.mono, +h3.mono, +h4.mono, +h5.mono, +h6.mono { + font-family: var(--font-mono); + font-weight: 400; + line-height: 1; + font-size: 6.2146892655vw; +} .p, p, @@ -433,145 +437,22 @@ pre { font-size: 3.3898305085vw; } -#app { - min-height: 100vh; -}/* Breakpoints */ -@keyframes flip-r { -50% { - transform: translateX(100%); - opacity: 0; -} -51% { - transform: translateX(-100%); - opacity: 0; -} -} -@keyframes flip-l { -50% { - transform: translateX(-100%); - opacity: 0; -} -51% { - transform: translateX(100%); - opacity: 0; -} -} -@keyframes flip-d { -50% { - transform: translateY(100%); - opacity: 0; -} -51% { - transform: translateY(-100%); - opacity: 0; -} -} -@keyframes flip-u { -50% { - transform: translateY(-100%); - opacity: 0; -} -51% { - transform: translateY(100%); - opacity: 0; -} -} -.editor { - padding-top: 2.2598870056vw; -} -.editor h1 { - font-weight: 700 !important; - font-family: var(--font-mono); - font-weight: 400; - line-height: 1; - font-size: 3.3898305085vw; -} -.editor h1:first-child { - font-family: var(--font-mono); - font-size: 3.3898305085vw; - font-weight: 400 !important; -} -.editor h1:first-child:first-child::first-letter { - font-family: var(--font-display); - font-size: 11.8644067797vw; -} -.editor h1.is-editor-empty:first-child::before { - color: var(--grey-100); - content: attr(data-placeholder); - pointer-events: none; - font-family: var(--font-mono); - font-size: 3.3898305085vw; - font-weight: 400 !important; -} -.editor h1.is-editor-empty:first-child::before:first-child::first-letter { - font-family: var(--font-display); - font-size: 11.8644067797vw; -} -.editor p strong { +.bold { font-weight: 700; } -.editor p em { - font-style: italic; + +#app { + min-height: 100vh; } -.editor hr::before { - content: "-----------------------------------------"; -} -.editor ul { - list-style-type: disc; -} -.editor ul li { - display: list-item; - margin-left: 1em; -} -.editor ol { - list-style-type: decimal; -} -.editor ol li { - display: list-item; - margin-left: 1.5em; -} -.editor ol li::marker { - font-family: var(--font-mono); - font-weight: 400; - line-height: 1; - font-size: 3.3898305085vw; -} -.editor a { - color: var(--theme-link); - cursor: pointer; -} -.editor .editor-wrap > div { - display: flex; - flex-direction: column; - gap: 5.6497175141vw; -} -.editor .editor-wrap > div:focus { - outline: none; -} -.editor .floating-menu, -.editor .bubble-menu { - display: flex; - gap: 1.4124293785vw; - border: 1px solid var(--grey-100); - color: var(--grey-100); - border-radius: 0.2em; - background: var(--theme-bg); -} -.editor .floating-menu button, -.editor .bubble-menu button { - cursor: pointer; - padding: 0.2em; - border-radius: 0.2em; -} -.editor .floating-menu button:hover, -.editor .bubble-menu button:hover { - background: var(--grey-100); + +::selection { color: var(--theme-bg); + background: var(--theme-accent); } -.editor .floating-menu button.active, -.editor .bubble-menu button.active { - background: var(--theme-fg); + +::-moz-selection { color: var(--theme-bg); + background: var(--theme-accent); }/* Breakpoints */ @keyframes flip-r { 50% { @@ -623,4 +504,394 @@ pre { } .container:not(.fonts-ready) { opacity: 0; +}/* Breakpoints */ +@keyframes flip-r { +50% { + transform: translateX(100%); + opacity: 0; +} +51% { + transform: translateX(-100%); + opacity: 0; +} +} +@keyframes flip-l { +50% { + transform: translateX(-100%); + opacity: 0; +} +51% { + transform: translateX(100%); + opacity: 0; +} +} +@keyframes flip-d { +50% { + transform: translateY(100%); + opacity: 0; +} +51% { + transform: translateY(-100%); + opacity: 0; +} +} +@keyframes flip-u { +50% { + transform: translateY(-100%); + opacity: 0; +} +51% { + transform: translateY(100%); + opacity: 0; +} +} +.category-row { + display: grid; + grid-template-columns: 7.3446327684vw 1fr; + width: 100%; + position: relative; + padding: 1.4124293785vw 0 4.2372881356vw; + cursor: pointer; +} +.category-row .index { + margin-top: 5.3672316384vw; +} +.category-row .title { + display: block; + width: 100%; + display: -webkit-box; + overflow: hidden; + text-overflow: ellipsis; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} +@media (max-width: 799px) { +.category-row .title { + -webkit-line-clamp: 2; +} +} +.category-row::after { + content: "----------------------------------------"; + position: absolute; + bottom: 0; + left: 0; +} +.category-row.router-link-exact-active { + cursor: default; +} +.category-row:hover:not(.router-link-exact-active) { + color: var(--theme-accent); +}/* Breakpoints */ +@keyframes flip-r { +50% { + transform: translateX(100%); + opacity: 0; +} +51% { + transform: translateX(-100%); + opacity: 0; +} +} +@keyframes flip-l { +50% { + transform: translateX(-100%); + opacity: 0; +} +51% { + transform: translateX(100%); + opacity: 0; +} +} +@keyframes flip-d { +50% { + transform: translateY(100%); + opacity: 0; +} +51% { + transform: translateY(-100%); + opacity: 0; +} +} +@keyframes flip-u { +50% { + transform: translateY(-100%); + opacity: 0; +} +51% { + transform: translateY(100%); + opacity: 0; +} +} +.note-row { + grid-template-columns: auto 1fr; + display: grid; + gap: 5.6497175141vw; + cursor: pointer; +} +.note-row .title { + width: 44.9152542373vw; + position: relative; +} +.note-row .title::after { + content: "(open)"; + position: absolute; + bottom: 0; + right: 0; + transform: translateX(100%); + font-weight: 700; + opacity: 0; +} +.note-row:hover { + color: var(--theme-accent); +} +.note-row:hover .title::after { + opacity: 1; +}/* Breakpoints */ +@keyframes flip-r { +50% { + transform: translateX(100%); + opacity: 0; +} +51% { + transform: translateX(-100%); + opacity: 0; +} +} +@keyframes flip-l { +50% { + transform: translateX(-100%); + opacity: 0; +} +51% { + transform: translateX(100%); + opacity: 0; +} +} +@keyframes flip-d { +50% { + transform: translateY(100%); + opacity: 0; +} +51% { + transform: translateY(-100%); + opacity: 0; +} +} +@keyframes flip-u { +50% { + transform: translateY(-100%); + opacity: 0; +} +51% { + transform: translateY(100%); + opacity: 0; +} +} +.directory { + padding-top: 5.0847457627vw; +} +.directory .label { + text-transform: uppercase; + margin: 4.802259887vw 0 6.7796610169vw; + font-family: var(--font-mono); + font-weight: 400; + line-height: 1; + font-size: 3.3898305085vw; +} +.directory .notes { + display: flex; + flex-direction: column; + gap: 3.9548022599vw; +}/* Breakpoints */ +@keyframes flip-r { +50% { + transform: translateX(100%); + opacity: 0; +} +51% { + transform: translateX(-100%); + opacity: 0; +} +} +@keyframes flip-l { +50% { + transform: translateX(-100%); + opacity: 0; +} +51% { + transform: translateX(100%); + opacity: 0; +} +} +@keyframes flip-d { +50% { + transform: translateY(100%); + opacity: 0; +} +51% { + transform: translateY(-100%); + opacity: 0; +} +} +@keyframes flip-u { +50% { + transform: translateY(-100%); + opacity: 0; +} +51% { + transform: translateY(100%); + opacity: 0; +} +} +.editor { + padding-top: 2.2598870056vw; + padding-bottom: 5.6497175141vw; +} +.editor h1 { + font-weight: 700 !important; + font-family: var(--font-mono); + font-weight: 400; + line-height: 1; + font-size: 3.3898305085vw; +} +.editor h1:first-child { + font-family: var(--font-mono); + font-size: 3.3898305085vw; + font-weight: 400 !important; +} +.editor h1:first-child:first-child::first-letter { + font-family: var(--font-display); + font-size: 11.8644067797vw; +} +.editor h1.is-editor-empty:first-child::before { + color: var(--grey-100); + content: attr(data-placeholder); + pointer-events: none; + font-family: var(--font-mono); + font-size: 3.3898305085vw; + font-weight: 400 !important; +} +.editor h1.is-editor-empty:first-child::before:first-child::first-letter { + font-family: var(--font-display); + font-size: 11.8644067797vw; +} +.editor p strong { + font-weight: 700; +} +.editor p em { + font-style: italic; +} +.editor hr::before { + content: "----------------------------------------"; + font-family: var(--font-mono); + font-weight: 400; + line-height: 1; + font-size: 3.3898305085vw; +} +.editor ul { + list-style-type: disc; +} +.editor ul li { + display: list-item; + margin-left: 1em; +} +.editor ol { + list-style-type: decimal; +} +.editor ol li { + display: list-item; + margin-left: 1.5em; +} +.editor ol li::marker { + font-family: var(--font-mono); + font-weight: 400; + line-height: 1; + font-size: 3.3898305085vw; +} +.editor a { + color: var(--theme-link); + cursor: pointer; +} +.editor .editor-wrap > div { + display: flex; + flex-direction: column; + gap: 5.6497175141vw; +} +.editor .editor-wrap > div:focus { + outline: none; +} +.editor .bubble-menu { + display: flex; + gap: 1.4124293785vw; + border: 1px solid var(--grey-100); + color: var(--grey-100); + border-radius: 0.2em; + background: var(--theme-bg); +} +.editor .bubble-menu button { + cursor: pointer; + padding: 0.2em; + border-radius: 0.2em; +} +.editor .bubble-menu button:hover { + background: var(--grey-100); + color: var(--theme-bg); +} +.editor .bubble-menu button.active { + background: var(--theme-fg); + color: var(--theme-bg); +}/* Breakpoints */ +@keyframes flip-r { +50% { + transform: translateX(100%); + opacity: 0; +} +51% { + transform: translateX(-100%); + opacity: 0; +} +} +@keyframes flip-l { +50% { + transform: translateX(-100%); + opacity: 0; +} +51% { + transform: translateX(100%); + opacity: 0; +} +} +@keyframes flip-d { +50% { + transform: translateY(100%); + opacity: 0; +} +51% { + transform: translateY(-100%); + opacity: 0; +} +} +@keyframes flip-u { +50% { + transform: translateY(-100%); + opacity: 0; +} +51% { + transform: translateY(100%); + opacity: 0; +} +} +.category .back { + display: block; + opacity: 0.25; + margin-top: 2.5423728814vw; +} +.category .category-row { + margin-top: 1.1299435028vw; +} +.category .notes { + display: flex; + flex-direction: column; + gap: 3.9548022599vw; + margin-top: 2.5423728814vw; } \ No newline at end of file diff --git a/out/renderer/assets/index-CnVkU_B_.js b/out/renderer/assets/index-Dv1qfmwr.js similarity index 92% rename from out/renderer/assets/index-CnVkU_B_.js rename to out/renderer/assets/index-Dv1qfmwr.js index 897b75a..b20c2de 100644 --- a/out/renderer/assets/index-CnVkU_B_.js +++ b/out/renderer/assets/index-Dv1qfmwr.js @@ -21,7 +21,7 @@ const remove = (arr, el) => { }; const hasOwnProperty$1 = Object.prototype.hasOwnProperty; const hasOwn = (val, key) => hasOwnProperty$1.call(val, key); -const isArray = Array.isArray; +const isArray$1 = Array.isArray; const isMap = (val) => toTypeString(val) === "[object Map]"; const isSet = (val) => toTypeString(val) === "[object Set]"; const isDate = (val) => toTypeString(val) === "[object Date]"; @@ -92,7 +92,7 @@ const getGlobalThis = () => { return _globalThis || (_globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {}); }; function normalizeStyle(value) { - if (isArray(value)) { + if (isArray$1(value)) { const res = {}; for (let i = 0; i < value.length; i++) { const item = value[i]; @@ -125,7 +125,7 @@ function normalizeClass(value) { let res = ""; if (isString(value)) { res = value; - } else if (isArray(value)) { + } else if (isArray$1(value)) { for (let i = 0; i < value.length; i++) { const normalized = normalizeClass(value[i]); if (normalized) { @@ -166,8 +166,8 @@ function looseEqual(a, b2) { if (aValidType || bValidType) { return a === b2; } - aValidType = isArray(a); - bValidType = isArray(b2); + aValidType = isArray$1(a); + bValidType = isArray$1(b2); if (aValidType || bValidType) { return aValidType && bValidType ? looseCompareArrays(a, b2) : false; } @@ -192,6 +192,44 @@ function looseEqual(a, b2) { } return String(a) === String(b2); } +const isRef$1 = (val) => { + return !!(val && val["__v_isRef"] === true); +}; +const toDisplayString = (val) => { + return isString(val) ? val : val == null ? "" : isArray$1(val) || isObject$1(val) && (val.toString === objectToString || !isFunction$1(val.toString)) ? isRef$1(val) ? toDisplayString(val.value) : JSON.stringify(val, replacer, 2) : String(val); +}; +const replacer = (_key, val) => { + if (isRef$1(val)) { + return replacer(_key, val.value); + } else if (isMap(val)) { + return { + [`Map(${val.size})`]: [...val.entries()].reduce( + (entries, [key, val2], i) => { + entries[stringifySymbol(key, i) + " =>"] = val2; + return entries; + }, + {} + ) + }; + } else if (isSet(val)) { + return { + [`Set(${val.size})`]: [...val.values()].map((v2) => stringifySymbol(v2)) + }; + } else if (isSymbol(val)) { + return stringifySymbol(val); + } else if (isObject$1(val) && !isArray$1(val) && !isPlainObject$1(val)) { + return String(val); + } + return val; +}; +const stringifySymbol = (v2, i = "") => { + var _a; + return ( + // Symbol.description in es2019+ so we need to cast here to pass + // the lib: es2016 check + isSymbol(v2) ? `Symbol(${(_a = v2.description) != null ? _a : i})` : v2 + ); +}; let activeEffectScope; class EffectScope { // TODO isolatedDeclarations "__v_skip" @@ -718,7 +756,7 @@ function trigger(target, type, key, newValue, oldValue, oldTarget) { if (type === "clear") { depsMap.forEach(run3); } else { - const targetIsArray = isArray(target); + const targetIsArray = isArray$1(target); const isArrayIndex = targetIsArray && isIntegerKey(key); if (targetIsArray && key === "length") { const newLength = Number(newValue); @@ -786,7 +824,7 @@ const arrayInstrumentations = { }, concat(...args) { return reactiveReadArray(this).concat( - ...args.map((x2) => isArray(x2) ? reactiveReadArray(x2) : x2) + ...args.map((x2) => isArray$1(x2) ? reactiveReadArray(x2) : x2) ); }, entries() { @@ -997,7 +1035,7 @@ class BaseReactiveHandler { } return; } - const targetIsArray = isArray(target); + const targetIsArray = isArray$1(target); if (!isReadonly2) { let fn; if (targetIsArray && (fn = arrayInstrumentations[key])) { @@ -1040,7 +1078,7 @@ class MutableReactiveHandler extends BaseReactiveHandler { } set(target, key, value, receiver) { let oldValue = target[key]; - const isArrayWithIntegerKey = isArray(target) && isIntegerKey(key); + const isArrayWithIntegerKey = isArray$1(target) && isIntegerKey(key); if (!this._isShallow) { const isOldValueReadonly = /* @__PURE__ */ isReadonly(oldValue); if (!/* @__PURE__ */ isShallow(value) && !/* @__PURE__ */ isReadonly(value)) { @@ -1092,7 +1130,7 @@ class MutableReactiveHandler extends BaseReactiveHandler { track( target, "iterate", - isArray(target) ? "length" : ITERATE_KEY + isArray$1(target) ? "length" : ITERATE_KEY ); return Reflect.ownKeys(target); } @@ -1599,7 +1637,7 @@ function watch$1(source, cb, options = EMPTY_OBJ) { } else if (/* @__PURE__ */ isReactive(source)) { getter = () => reactiveGetter(source); forceTrigger = true; - } else if (isArray(source)) { + } else if (isArray$1(source)) { isMultiSource = true; forceTrigger = source.some((s) => /* @__PURE__ */ isReactive(s) || /* @__PURE__ */ isShallow(s)); getter = () => source.map((s) => { @@ -1733,7 +1771,7 @@ function traverse(value, depth = Infinity, seen) { depth--; if (/* @__PURE__ */ isRef(value)) { traverse(value.value, depth, seen); - } else if (isArray(value)) { + } else if (isArray$1(value)) { for (let i = 0; i < value.length; i++) { traverse(value[i], depth, seen); } @@ -1876,7 +1914,7 @@ function callWithAsyncErrorHandling(fn, instance, type, args) { } return res; } - if (isArray(fn)) { + if (isArray$1(fn)) { const values = []; for (let i = 0; i < fn.length; i++) { values.push(callWithAsyncErrorHandling(fn[i], instance, type, args)); @@ -1933,7 +1971,7 @@ function nextTick(fn) { const p2 = currentFlushPromise || resolvedPromise; return fn ? p2.then(this ? fn.bind(this) : fn) : p2; } -function findInsertionIndex(id) { +function findInsertionIndex$1(id) { let start = flushIndex + 1; let end = queue.length; while (start < end) { @@ -1956,7 +1994,7 @@ function queueJob(job) { !(job.flags & 2) && jobId >= getId(lastJob)) { queue.push(job); } else { - queue.splice(findInsertionIndex(jobId), 0, job); + queue.splice(findInsertionIndex$1(jobId), 0, job); } job.flags |= 1; queueFlush(); @@ -1968,7 +2006,7 @@ function queueFlush() { } } function queuePostFlushCb(cb) { - if (!isArray(cb)) { + if (!isArray$1(cb)) { if (activePostFlushCbs && cb.id === -1) { activePostFlushCbs.splice(postFlushIndex + 1, 0, cb); } else if (!(cb.flags & 1)) { @@ -2263,11 +2301,11 @@ function isTemplateRefKey(refs, key) { } const pendingSetRefMap = /* @__PURE__ */ new WeakMap(); function setRef(rawRef, oldRawRef, parentSuspense, vnode, isUnmount = false) { - if (isArray(rawRef)) { + if (isArray$1(rawRef)) { rawRef.forEach( (r, i) => setRef( r, - oldRawRef && (isArray(oldRawRef) ? oldRawRef[i] : oldRawRef), + oldRawRef && (isArray$1(oldRawRef) ? oldRawRef[i] : oldRawRef), parentSuspense, vnode, isUnmount @@ -2325,9 +2363,9 @@ function setRef(rawRef, oldRawRef, parentSuspense, vnode, isUnmount = false) { if (rawRef.f) { const existing = _isString ? canSetSetupRef(ref3) ? setupState[ref3] : refs[ref3] : canSetRef() || !rawRef.k ? ref3.value : refs[rawRef.k]; if (isUnmount) { - isArray(existing) && remove(existing, refValue); + isArray$1(existing) && remove(existing, refValue); } else { - if (!isArray(existing)) { + if (!isArray$1(existing)) { if (_isString) { refs[ref3] = [refValue]; if (canSetSetupRef(ref3)) { @@ -2464,7 +2502,85 @@ const onRenderTracked = createHook("rtc"); function onErrorCaptured(hook, target = currentInstance) { injectHook("ec", hook, target); } +const COMPONENTS = "components"; +function resolveComponent(name, maybeSelfReference) { + return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name; +} const NULL_DYNAMIC_COMPONENT = /* @__PURE__ */ Symbol.for("v-ndc"); +function resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) { + const instance = currentRenderingInstance || currentInstance; + if (instance) { + const Component = instance.type; + { + const selfName = getComponentName( + Component, + false + ); + if (selfName && (selfName === name || selfName === camelize(name) || selfName === capitalize(camelize(name)))) { + return Component; + } + } + const res = ( + // local registration + // check instance[type] first which is resolved for options API + resolve(instance[type] || Component[type], name) || // global registration + resolve(instance.appContext[type], name) + ); + if (!res && maybeSelfReference) { + return Component; + } + return res; + } +} +function resolve(registry, name) { + return registry && (registry[name] || registry[camelize(name)] || registry[capitalize(camelize(name))]); +} +function renderList(source, renderItem, cache, index2) { + let ret; + const cached = cache; + const sourceIsArray = isArray$1(source); + if (sourceIsArray || isString(source)) { + const sourceIsReactiveArray = sourceIsArray && /* @__PURE__ */ isReactive(source); + let needsWrap = false; + let isReadonlySource = false; + if (sourceIsReactiveArray) { + needsWrap = !/* @__PURE__ */ isShallow(source); + isReadonlySource = /* @__PURE__ */ isReadonly(source); + source = shallowReadArray(source); + } + ret = new Array(source.length); + for (let i = 0, l = source.length; i < l; i++) { + ret[i] = renderItem( + needsWrap ? isReadonlySource ? toReadonly(toReactive(source[i])) : toReactive(source[i]) : source[i], + i, + void 0, + cached + ); + } + } else if (typeof source === "number") { + ret = new Array(source); + for (let i = 0; i < source; i++) { + ret[i] = renderItem(i + 1, i, void 0, cached); + } + } else if (isObject$1(source)) { + if (source[Symbol.iterator]) { + ret = Array.from( + source, + (item, i) => renderItem(item, i, void 0, cached) + ); + } else { + const keys2 = Object.keys(source); + ret = new Array(keys2.length); + for (let i = 0, l = keys2.length; i < l; i++) { + const key = keys2[i]; + ret[i] = renderItem(source[key], key, i, cached); + } + } + } else { + ret = []; + } + return ret; +} function renderSlot(slots, name, props = {}, fallback, noSlotted) { if (currentRenderingInstance.ce || currentRenderingInstance.parent && isAsyncWrapper(currentRenderingInstance.parent) && currentRenderingInstance.parent.ce) { const hasProps = Object.keys(props).length > 0; @@ -2634,7 +2750,7 @@ const PublicInstanceProxyHandlers = { } }; function normalizePropsOrEmits(props) { - return isArray(props) ? props.reduce( + return isArray$1(props) ? props.reduce( (normalized, p2) => (normalized[p2] = null, normalized), {} ) : props; @@ -2735,7 +2851,7 @@ function applyOptions(instance) { callHook(created, instance, "c"); } function registerLifecycleHook(register, hook) { - if (isArray(hook)) { + if (isArray$1(hook)) { hook.forEach((_hook) => register(_hook.bind(publicThis))); } else if (hook) { register(hook.bind(publicThis)); @@ -2753,7 +2869,7 @@ function applyOptions(instance) { registerLifecycleHook(onBeforeUnmount, beforeUnmount); registerLifecycleHook(onUnmounted, unmounted); registerLifecycleHook(onServerPrefetch, serverPrefetch); - if (isArray(expose)) { + if (isArray$1(expose)) { if (expose.length) { const exposed = instance.exposed || (instance.exposed = {}); expose.forEach((key) => { @@ -2780,7 +2896,7 @@ function applyOptions(instance) { } } function resolveInjections(injectOptions, ctx, checkDuplicateProperties = NOOP) { - if (isArray(injectOptions)) { + if (isArray$1(injectOptions)) { injectOptions = normalizeInject(injectOptions); } for (const key in injectOptions) { @@ -2813,7 +2929,7 @@ function resolveInjections(injectOptions, ctx, checkDuplicateProperties = NOOP) } function callHook(hook, instance, type) { callWithAsyncErrorHandling( - isArray(hook) ? hook.map((h2) => h2.bind(instance.proxy)) : hook.bind(instance.proxy), + isArray$1(hook) ? hook.map((h2) => h2.bind(instance.proxy)) : hook.bind(instance.proxy), instance, type ); @@ -2832,7 +2948,7 @@ function createWatcher(raw, ctx, publicThis, key) { watch(getter, raw.bind(publicThis)); } } else if (isObject$1(raw)) { - if (isArray(raw)) { + if (isArray$1(raw)) { raw.forEach((r) => createWatcher(r, ctx, publicThis, key)); } else { const handler = isFunction$1(raw.handler) ? raw.handler.bind(publicThis) : ctx[raw.handler]; @@ -2862,24 +2978,24 @@ function resolveMergedOptions(instance) { resolved = {}; if (globalMixins.length) { globalMixins.forEach( - (m2) => mergeOptions(resolved, m2, optionMergeStrategies, true) + (m2) => mergeOptions$1(resolved, m2, optionMergeStrategies, true) ); } - mergeOptions(resolved, base2, optionMergeStrategies); + mergeOptions$1(resolved, base2, optionMergeStrategies); } if (isObject$1(base2)) { cache.set(base2, resolved); } return resolved; } -function mergeOptions(to, from2, strats, asMixin = false) { +function mergeOptions$1(to, from2, strats, asMixin = false) { const { mixins, extends: extendsOptions } = from2; if (extendsOptions) { - mergeOptions(to, extendsOptions, strats, true); + mergeOptions$1(to, extendsOptions, strats, true); } if (mixins) { mixins.forEach( - (m2) => mergeOptions(to, m2, strats, true) + (m2) => mergeOptions$1(to, m2, strats, true) ); } for (const key in from2) { @@ -2940,7 +3056,7 @@ function mergeInject(to, from2) { return mergeObjectOptions(normalizeInject(to), normalizeInject(from2)); } function normalizeInject(raw) { - if (isArray(raw)) { + if (isArray$1(raw)) { const res = {}; for (let i = 0; i < raw.length; i++) { res[raw[i]] = raw[i]; @@ -2957,7 +3073,7 @@ function mergeObjectOptions(to, from2) { } function mergeEmitsOrPropsOptions(to, from2) { if (to) { - if (isArray(to) && isArray(from2)) { + if (isArray$1(to) && isArray$1(from2)) { return [.../* @__PURE__ */ new Set([...to, ...from2])]; } return extend( @@ -3012,7 +3128,7 @@ function createAppAPI(render, hydrate) { const installedPlugins = /* @__PURE__ */ new WeakSet(); const pluginCleanupFns = []; let isMounted = false; - const app = context.app = { + const app2 = context.app = { _uid: uid$1++, _component: rootComponent, _props: rootProps, @@ -3029,12 +3145,12 @@ function createAppAPI(render, hydrate) { if (installedPlugins.has(plugin)) ; else if (plugin && isFunction$1(plugin.install)) { installedPlugins.add(plugin); - plugin.install(app, ...options); + plugin.install(app2, ...options); } else if (isFunction$1(plugin)) { installedPlugins.add(plugin); - plugin(app, ...options); + plugin(app2, ...options); } else ; - return app; + return app2; }, mixin(mixin) { { @@ -3042,25 +3158,25 @@ function createAppAPI(render, hydrate) { context.mixins.push(mixin); } } - return app; + return app2; }, component(name, component) { if (!component) { return context.components[name]; } context.components[name] = component; - return app; + return app2; }, directive(name, directive) { if (!directive) { return context.directives[name]; } context.directives[name] = directive; - return app; + return app2; }, mount(rootContainer, isHydrate, namespace) { if (!isMounted) { - const vnode = app._ceVNode || createVNode(rootComponent, rootProps); + const vnode = app2._ceVNode || createVNode(rootComponent, rootProps); vnode.appContext = context; if (namespace === true) { namespace = "svg"; @@ -3071,8 +3187,8 @@ function createAppAPI(render, hydrate) { render(vnode, rootContainer, namespace); } isMounted = true; - app._container = rootContainer; - rootContainer.__vue_app__ = app; + app2._container = rootContainer; + rootContainer.__vue_app__ = app2; return getComponentPublicInstance(vnode.component); } }, @@ -3083,20 +3199,20 @@ function createAppAPI(render, hydrate) { if (isMounted) { callWithAsyncErrorHandling( pluginCleanupFns, - app._instance, + app2._instance, 16 ); - render(null, app._container); - delete app._container.__vue_app__; + render(null, app2._container); + delete app2._container.__vue_app__; } }, provide(key, value) { context.provides[key] = value; - return app; + return app2; }, runWithContext(fn) { const lastApp = currentApp; - currentApp = app; + currentApp = app2; try { return fn(); } finally { @@ -3104,7 +3220,7 @@ function createAppAPI(render, hydrate) { } } }; - return app; + return app2; }; } let currentApp = null; @@ -3189,7 +3305,7 @@ function normalizeEmitsOptions(comp, appContext, asMixin = false) { } return null; } - if (isArray(raw)) { + if (isArray$1(raw)) { raw.forEach((key) => normalized[key] = null); } else { extend(normalized, raw); @@ -3636,7 +3752,7 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { } return EMPTY_ARR; } - if (isArray(raw)) { + if (isArray$1(raw)) { for (let i = 0; i < raw.length; i++) { const normalizedKey = camelize(raw[i]); if (validatePropName(normalizedKey)) { @@ -3648,11 +3764,11 @@ function normalizePropsOptions(comp, appContext, asMixin = false) { const normalizedKey = camelize(key); if (validatePropName(normalizedKey)) { const opt = raw[key]; - const prop = normalized[normalizedKey] = isArray(opt) || isFunction$1(opt) ? { type: opt } : extend({}, opt); + const prop = normalized[normalizedKey] = isArray$1(opt) || isFunction$1(opt) ? { type: opt } : extend({}, opt); const propType = prop.type; let shouldCast = false; let shouldCastTrue = true; - if (isArray(propType)) { + if (isArray$1(propType)) { for (let index2 = 0; index2 < propType.length; ++index2) { const type = propType[index2]; const typeName = isFunction$1(type) && type.name; @@ -3693,8 +3809,8 @@ function validatePropName(key) { return false; } const isInternalKey = (key) => key === "_" || key === "_ctx" || key === "$stable"; -const normalizeSlotValue = (value) => isArray(value) ? value.map(normalizeVNode) : [normalizeVNode(value)]; -const normalizeSlot = (key, rawSlot, ctx) => { +const normalizeSlotValue = (value) => isArray$1(value) ? value.map(normalizeVNode) : [normalizeVNode(value)]; +const normalizeSlot$1 = (key, rawSlot, ctx) => { if (rawSlot._n) { return rawSlot; } @@ -3711,7 +3827,7 @@ const normalizeObjectSlots = (rawSlots, slots, instance) => { if (isInternalKey(key)) continue; const value = rawSlots[key]; if (isFunction$1(value)) { - slots[key] = normalizeSlot(key, value, ctx); + slots[key] = normalizeSlot$1(key, value, ctx); } else if (value != null) { const normalized = normalizeSlotValue(value); slots[key] = () => normalized; @@ -5049,7 +5165,7 @@ function needTransition(parentSuspense, transition) { function traverseStaticChildren(n1, n2, shallow = false) { const ch1 = n1.children; const ch2 = n2.children; - if (isArray(ch1) && isArray(ch2)) { + if (isArray$1(ch1) && isArray$1(ch2)) { for (let i = 0; i < ch1.length; i++) { const c1 = ch1[i]; let c2 = ch2[i]; @@ -5142,7 +5258,7 @@ function resolveAsyncComponentPlaceholder(anchorVnode) { const isSuspense = (type) => type.__isSuspense; function queueEffectWithSuspense(fn, suspense) { if (suspense && suspense.pendingBranch) { - if (isArray(fn)) { + if (isArray$1(fn)) { suspense.effects.push(...fn); } else { suspense.effects.push(fn); @@ -5307,7 +5423,7 @@ function _createVNode(type, props = null, children = null, patchFlag = 0, dynami props.class = normalizeClass(klass); } if (isObject$1(style2)) { - if (/* @__PURE__ */ isProxy(style2) && !isArray(style2)) { + if (/* @__PURE__ */ isProxy(style2) && !isArray$1(style2)) { style2 = extend({}, style2); } props.style = normalizeStyle(style2); @@ -5342,7 +5458,7 @@ function cloneVNode(vnode, extraProps, mergeRef = false, cloneTransition = false // #2078 in the case of // if the vnode itself already has a ref, cloneVNode will need to merge // the refs so the single vnode can be set on multiple refs - mergeRef && ref3 ? isArray(ref3) ? ref3.concat(normalizeRef(extraProps)) : [ref3, normalizeRef(extraProps)] : normalizeRef(extraProps) + mergeRef && ref3 ? isArray$1(ref3) ? ref3.concat(normalizeRef(extraProps)) : [ref3, normalizeRef(extraProps)] : normalizeRef(extraProps) ) : ref3, scopeId: vnode.scopeId, slotScopeIds: vnode.slotScopeIds, @@ -5393,7 +5509,7 @@ function createCommentVNode(text = "", asBlock = false) { function normalizeVNode(child) { if (child == null || typeof child === "boolean") { return createVNode(Comment); - } else if (isArray(child)) { + } else if (isArray$1(child)) { return createVNode( Fragment$1, null, @@ -5414,7 +5530,7 @@ function normalizeChildren(vnode, children) { const { shapeFlag } = vnode; if (children == null) { children = null; - } else if (isArray(children)) { + } else if (isArray$1(children)) { type = 16; } else if (typeof children === "object") { if (shapeFlag & (1 | 64)) { @@ -5468,7 +5584,7 @@ function mergeProps(...args) { } else if (isOn(key)) { const existing = ret[key]; const incoming = toMerge[key]; - if (incoming && existing !== incoming && !(isArray(existing) && existing.includes(incoming))) { + if (incoming && existing !== incoming && !(isArray$1(existing) && existing.includes(incoming))) { ret[key] = existing ? [].concat(existing, incoming) : incoming; } } else if (key !== "") { @@ -5772,7 +5888,7 @@ function h$1(type, propsOrChildren, children) { setBlockTracking(-1); const l = arguments.length; if (l === 2) { - if (isObject$1(propsOrChildren) && !isArray(propsOrChildren)) { + if (isObject$1(propsOrChildren) && !isArray$1(propsOrChildren)) { if (isVNode(propsOrChildren)) { return createVNode(type, null, [propsOrChildren]); } @@ -5940,7 +6056,7 @@ function patchStyle(el, prev, next) { } const importantRE = /\s*!important$/; function setStyle(style2, name, val) { - if (isArray(val)) { + if (isArray$1(val)) { val.forEach((v2) => setStyle(style2, name, v2)); } else { if (val == null) val = ""; @@ -6105,7 +6221,7 @@ function createInvoker(initialValue, instance) { return invoker; } function patchStopImmediatePropagation(e, value) { - if (isArray(value)) { + if (isArray$1(value)) { const originalStop = e.stopImmediatePropagation; e.stopImmediatePropagation = () => { originalStop.call(e); @@ -6191,12 +6307,12 @@ function ensureRenderer() { return renderer || (renderer = createRenderer(rendererOptions)); } const createApp = ((...args) => { - const app = ensureRenderer().createApp(...args); - const { mount } = app; - app.mount = (containerOrSelector) => { + const app2 = ensureRenderer().createApp(...args); + const { mount } = app2; + app2.mount = (containerOrSelector) => { const container = normalizeContainer(containerOrSelector); if (!container) return; - const component = app._component; + const component = app2._component; if (!isFunction$1(component) && !component.render && !component.template) { component.template = container.innerHTML; } @@ -6210,7 +6326,7 @@ const createApp = ((...args) => { } return proxy; }; - return app; + return app2; }); function resolveRootNamespace(container) { if (container instanceof SVGElement) { @@ -7555,7 +7671,7 @@ var TempusImpl = class { } }; var Tempus = new TempusImpl(); -const _sfc_main$2 = { +const _sfc_main$6 = { __name: "Lenis", props: { root: { @@ -8810,6 +8926,1920 @@ function useWindowSize(options = {}) { height }; } +const _sfc_main$5 = { + __name: "App", + setup(__props) { + const { height } = /* @__PURE__ */ useWindowSize(); + const classes = computed(() => [ + "container", + { "fonts-ready": !fontsLoading.value }, + "theme-dark" + ]); + const fontsLoading = /* @__PURE__ */ ref(true); + onMounted(async () => { + loadFonts([ + { + name: "Leibniz Fraktur", + weights: [400] + }, + { + name: "Geist Mono", + weights: [400, 700] + } + ]).then(() => { + fontsLoading.value = false; + }).catch(() => { + fontsLoading.value = false; + }); + }); + const styles = computed(() => ({ + "--vh": height.value ? height.value / 100 + "px" : "100vh" + })); + return (_ctx, _cache) => { + const _component_router_view = resolveComponent("router-view"); + return openBlock(), createBlock(_sfc_main$6, { + root: "", + options: { duration: 1 } + }, { + default: withCtx(() => [ + createBaseVNode("div", { + class: normalizeClass(classes.value), + style: normalizeStyle(styles.value) + }, [ + (openBlock(), createBlock(_component_router_view, { + key: _ctx.$route.fullPath + })) + ], 6) + ]), + _: 1 + }); + }; + } +}; +const isBrowser = typeof document !== "undefined"; +function isRouteComponent(component) { + return typeof component === "object" || "displayName" in component || "props" in component || "__vccOpts" in component; +} +function isESModule(obj) { + return obj.__esModule || obj[Symbol.toStringTag] === "Module" || obj.default && isRouteComponent(obj.default); +} +const assign$1 = Object.assign; +function applyToParams(fn, params) { + const newParams = {}; + for (const key in params) { + const value = params[key]; + newParams[key] = isArray(value) ? value.map(fn) : fn(value); + } + return newParams; +} +const noop$1 = () => { +}; +const isArray = Array.isArray; +function mergeOptions(defaults2, partialOptions) { + const options = {}; + for (const key in defaults2) options[key] = key in partialOptions ? partialOptions[key] : defaults2[key]; + return options; +} +let ErrorTypes = /* @__PURE__ */ (function(ErrorTypes2) { + ErrorTypes2[ErrorTypes2["MATCHER_NOT_FOUND"] = 1] = "MATCHER_NOT_FOUND"; + ErrorTypes2[ErrorTypes2["NAVIGATION_GUARD_REDIRECT"] = 2] = "NAVIGATION_GUARD_REDIRECT"; + ErrorTypes2[ErrorTypes2["NAVIGATION_ABORTED"] = 4] = "NAVIGATION_ABORTED"; + ErrorTypes2[ErrorTypes2["NAVIGATION_CANCELLED"] = 8] = "NAVIGATION_CANCELLED"; + ErrorTypes2[ErrorTypes2["NAVIGATION_DUPLICATED"] = 16] = "NAVIGATION_DUPLICATED"; + return ErrorTypes2; +})({}); +const NavigationFailureSymbol = /* @__PURE__ */ Symbol(""); +({ + [ErrorTypes.MATCHER_NOT_FOUND]({ location: location2, currentLocation }) { + return `No match for + ${JSON.stringify(location2)}${currentLocation ? "\nwhile being at\n" + JSON.stringify(currentLocation) : ""}`; + }, + [ErrorTypes.NAVIGATION_GUARD_REDIRECT]({ from: from2, to }) { + return `Redirected from "${from2.fullPath}" to "${stringifyRoute(to)}" via a navigation guard.`; + }, + [ErrorTypes.NAVIGATION_ABORTED]({ from: from2, to }) { + return `Navigation aborted from "${from2.fullPath}" to "${to.fullPath}" via a navigation guard.`; + }, + [ErrorTypes.NAVIGATION_CANCELLED]({ from: from2, to }) { + return `Navigation cancelled from "${from2.fullPath}" to "${to.fullPath}" with a new navigation.`; + }, + [ErrorTypes.NAVIGATION_DUPLICATED]({ from: from2, to }) { + return `Avoided redundant navigation to current location: "${from2.fullPath}".`; + } +}); +function createRouterError(type, params) { + return assign$1(/* @__PURE__ */ new Error(), { + type, + [NavigationFailureSymbol]: true + }, params); +} +function isNavigationFailure(error, type) { + return error instanceof Error && NavigationFailureSymbol in error && (type == null || !!(error.type & type)); +} +const propertiesToLog = [ + "params", + "query", + "hash" +]; +function stringifyRoute(to) { + if (typeof to === "string") return to; + if (to.path != null) return to.path; + const location2 = {}; + for (const key of propertiesToLog) if (key in to) location2[key] = to[key]; + return JSON.stringify(location2, null, 2); +} +const matchedRouteKey = /* @__PURE__ */ Symbol(""); +const viewDepthKey = /* @__PURE__ */ Symbol(""); +const routerKey = /* @__PURE__ */ Symbol(""); +const routeLocationKey = /* @__PURE__ */ Symbol(""); +const routerViewLocationKey = /* @__PURE__ */ Symbol(""); +function useRouter() { + return inject(routerKey); +} +function useRoute(_name) { + return inject(routeLocationKey); +} +const HASH_RE = /#/g; +const AMPERSAND_RE = /&/g; +const SLASH_RE = /\//g; +const EQUAL_RE = /=/g; +const IM_RE = /\?/g; +const PLUS_RE = /\+/g; +const ENC_BRACKET_OPEN_RE = /%5B/g; +const ENC_BRACKET_CLOSE_RE = /%5D/g; +const ENC_CARET_RE = /%5E/g; +const ENC_BACKTICK_RE = /%60/g; +const ENC_CURLY_OPEN_RE = /%7B/g; +const ENC_PIPE_RE = /%7C/g; +const ENC_CURLY_CLOSE_RE = /%7D/g; +const ENC_SPACE_RE = /%20/g; +function commonEncode(text) { + return text == null ? "" : encodeURI("" + text).replace(ENC_PIPE_RE, "|").replace(ENC_BRACKET_OPEN_RE, "[").replace(ENC_BRACKET_CLOSE_RE, "]"); +} +function encodeHash(text) { + return commonEncode(text).replace(ENC_CURLY_OPEN_RE, "{").replace(ENC_CURLY_CLOSE_RE, "}").replace(ENC_CARET_RE, "^"); +} +function encodeQueryValue(text) { + return commonEncode(text).replace(PLUS_RE, "%2B").replace(ENC_SPACE_RE, "+").replace(HASH_RE, "%23").replace(AMPERSAND_RE, "%26").replace(ENC_BACKTICK_RE, "`").replace(ENC_CURLY_OPEN_RE, "{").replace(ENC_CURLY_CLOSE_RE, "}").replace(ENC_CARET_RE, "^"); +} +function encodeQueryKey(text) { + return encodeQueryValue(text).replace(EQUAL_RE, "%3D"); +} +function encodePath(text) { + return commonEncode(text).replace(HASH_RE, "%23").replace(IM_RE, "%3F"); +} +function encodeParam(text) { + return encodePath(text).replace(SLASH_RE, "%2F"); +} +function decode(text) { + if (text == null) return null; + try { + return decodeURIComponent("" + text); + } catch (err) { + } + return "" + text; +} +const TRAILING_SLASH_RE = /\/$/; +const removeTrailingSlash = (path) => path.replace(TRAILING_SLASH_RE, ""); +function parseURL(parseQuery2, location2, currentLocation = "/") { + let path, query = {}, searchString = "", hash = ""; + const hashPos = location2.indexOf("#"); + let searchPos = location2.indexOf("?"); + searchPos = hashPos >= 0 && searchPos > hashPos ? -1 : searchPos; + if (searchPos >= 0) { + path = location2.slice(0, searchPos); + searchString = location2.slice(searchPos, hashPos > 0 ? hashPos : location2.length); + query = parseQuery2(searchString.slice(1)); + } + if (hashPos >= 0) { + path = path || location2.slice(0, hashPos); + hash = location2.slice(hashPos, location2.length); + } + path = resolveRelativePath(path != null ? path : location2, currentLocation); + return { + fullPath: path + searchString + hash, + path, + query, + hash: decode(hash) + }; +} +function stringifyURL(stringifyQuery2, location2) { + const query = location2.query ? stringifyQuery2(location2.query) : ""; + return location2.path + (query && "?") + query + (location2.hash || ""); +} +function stripBase(pathname, base2) { + if (!base2 || !pathname.toLowerCase().startsWith(base2.toLowerCase())) return pathname; + return pathname.slice(base2.length) || "/"; +} +function isSameRouteLocation(stringifyQuery2, a, b2) { + const aLastIndex = a.matched.length - 1; + const bLastIndex = b2.matched.length - 1; + return aLastIndex > -1 && aLastIndex === bLastIndex && isSameRouteRecord(a.matched[aLastIndex], b2.matched[bLastIndex]) && isSameRouteLocationParams(a.params, b2.params) && stringifyQuery2(a.query) === stringifyQuery2(b2.query) && a.hash === b2.hash; +} +function isSameRouteRecord(a, b2) { + return (a.aliasOf || a) === (b2.aliasOf || b2); +} +function isSameRouteLocationParams(a, b2) { + if (Object.keys(a).length !== Object.keys(b2).length) return false; + for (var key in a) if (!isSameRouteLocationParamsValue(a[key], b2[key])) return false; + return true; +} +function isSameRouteLocationParamsValue(a, b2) { + return isArray(a) ? isEquivalentArray(a, b2) : isArray(b2) ? isEquivalentArray(b2, a) : (a && a.valueOf()) === (b2 && b2.valueOf()); +} +function isEquivalentArray(a, b2) { + return isArray(b2) ? a.length === b2.length && a.every((value, i) => value === b2[i]) : a.length === 1 && a[0] === b2; +} +function resolveRelativePath(to, from2) { + if (to.startsWith("/")) return to; + if (!to) return from2; + const fromSegments = from2.split("/"); + const toSegments = to.split("/"); + const lastToSegment = toSegments[toSegments.length - 1]; + if (lastToSegment === ".." || lastToSegment === ".") toSegments.push(""); + let position = fromSegments.length - 1; + let toPosition; + let segment; + for (toPosition = 0; toPosition < toSegments.length; toPosition++) { + segment = toSegments[toPosition]; + if (segment === ".") continue; + if (segment === "..") { + if (position > 1) position--; + } else break; + } + return fromSegments.slice(0, position).join("/") + "/" + toSegments.slice(toPosition).join("/"); +} +const START_LOCATION_NORMALIZED = { + path: "/", + name: void 0, + params: {}, + query: {}, + hash: "", + fullPath: "/", + matched: [], + meta: {}, + redirectedFrom: void 0 +}; +let NavigationType = /* @__PURE__ */ (function(NavigationType2) { + NavigationType2["pop"] = "pop"; + NavigationType2["push"] = "push"; + return NavigationType2; +})({}); +let NavigationDirection = /* @__PURE__ */ (function(NavigationDirection2) { + NavigationDirection2["back"] = "back"; + NavigationDirection2["forward"] = "forward"; + NavigationDirection2["unknown"] = ""; + return NavigationDirection2; +})({}); +function normalizeBase(base2) { + if (!base2) if (isBrowser) { + const baseEl = document.querySelector("base"); + base2 = baseEl && baseEl.getAttribute("href") || "/"; + base2 = base2.replace(/^\w+:\/\/[^\/]+/, ""); + } else base2 = "/"; + if (base2[0] !== "/" && base2[0] !== "#") base2 = "/" + base2; + return removeTrailingSlash(base2); +} +const BEFORE_HASH_RE = /^[^#]+#/; +function createHref(base2, location2) { + return base2.replace(BEFORE_HASH_RE, "#") + location2; +} +function getElementPosition(el, offset2) { + const docRect = document.documentElement.getBoundingClientRect(); + const elRect = el.getBoundingClientRect(); + return { + behavior: offset2.behavior, + left: elRect.left - docRect.left - (offset2.left || 0), + top: elRect.top - docRect.top - (offset2.top || 0) + }; +} +const computeScrollPosition = () => ({ + left: window.scrollX, + top: window.scrollY +}); +function scrollToPosition(position) { + let scrollToOptions; + if ("el" in position) { + const positionEl = position.el; + const isIdSelector = typeof positionEl === "string" && positionEl.startsWith("#"); + const el = typeof positionEl === "string" ? isIdSelector ? document.getElementById(positionEl.slice(1)) : document.querySelector(positionEl) : positionEl; + if (!el) { + return; + } + scrollToOptions = getElementPosition(el, position); + } else scrollToOptions = position; + if ("scrollBehavior" in document.documentElement.style) window.scrollTo(scrollToOptions); + else window.scrollTo(scrollToOptions.left != null ? scrollToOptions.left : window.scrollX, scrollToOptions.top != null ? scrollToOptions.top : window.scrollY); +} +function getScrollKey(path, delta) { + return (history.state ? history.state.position - delta : -1) + path; +} +const scrollPositions = /* @__PURE__ */ new Map(); +function saveScrollPosition(key, scrollPosition) { + scrollPositions.set(key, scrollPosition); +} +function getSavedScrollPosition(key) { + const scroll = scrollPositions.get(key); + scrollPositions.delete(key); + return scroll; +} +function isRouteLocation(route) { + return typeof route === "string" || route && typeof route === "object"; +} +function isRouteName(name) { + return typeof name === "string" || typeof name === "symbol"; +} +function parseQuery(search) { + const query = {}; + if (search === "" || search === "?") return query; + const searchParams = (search[0] === "?" ? search.slice(1) : search).split("&"); + for (let i = 0; i < searchParams.length; ++i) { + const searchParam = searchParams[i].replace(PLUS_RE, " "); + const eqPos = searchParam.indexOf("="); + const key = decode(eqPos < 0 ? searchParam : searchParam.slice(0, eqPos)); + const value = eqPos < 0 ? null : decode(searchParam.slice(eqPos + 1)); + if (key in query) { + let currentValue = query[key]; + if (!isArray(currentValue)) currentValue = query[key] = [currentValue]; + currentValue.push(value); + } else query[key] = value; + } + return query; +} +function stringifyQuery(query) { + let search = ""; + for (let key in query) { + const value = query[key]; + key = encodeQueryKey(key); + if (value == null) { + if (value !== void 0) search += (search.length ? "&" : "") + key; + continue; + } + (isArray(value) ? value.map((v2) => v2 && encodeQueryValue(v2)) : [value && encodeQueryValue(value)]).forEach((value2) => { + if (value2 !== void 0) { + search += (search.length ? "&" : "") + key; + if (value2 != null) search += "=" + value2; + } + }); + } + return search; +} +function normalizeQuery(query) { + const normalizedQuery = {}; + for (const key in query) { + const value = query[key]; + if (value !== void 0) normalizedQuery[key] = isArray(value) ? value.map((v2) => v2 == null ? null : "" + v2) : value == null ? value : "" + value; + } + return normalizedQuery; +} +function useCallbacks() { + let handlers2 = []; + function add(handler) { + handlers2.push(handler); + return () => { + const i = handlers2.indexOf(handler); + if (i > -1) handlers2.splice(i, 1); + }; + } + function reset2() { + handlers2 = []; + } + return { + add, + list: () => handlers2.slice(), + reset: reset2 + }; +} +function guardToPromiseFn(guard, to, from2, record, name, runWithContext = (fn) => fn()) { + const enterCallbackArray = record && (record.enterCallbacks[name] = record.enterCallbacks[name] || []); + return () => new Promise((resolve2, reject) => { + const next = (valid) => { + if (valid === false) reject(createRouterError(ErrorTypes.NAVIGATION_ABORTED, { + from: from2, + to + })); + else if (valid instanceof Error) reject(valid); + else if (isRouteLocation(valid)) reject(createRouterError(ErrorTypes.NAVIGATION_GUARD_REDIRECT, { + from: to, + to: valid + })); + else { + if (enterCallbackArray && record.enterCallbacks[name] === enterCallbackArray && typeof valid === "function") enterCallbackArray.push(valid); + resolve2(); + } + }; + const guardReturn = runWithContext(() => guard.call(record && record.instances[name], to, from2, next)); + let guardCall = Promise.resolve(guardReturn); + if (guard.length < 3) guardCall = guardCall.then(next); + guardCall.catch((err) => reject(err)); + }); +} +function extractComponentsGuards(matched, guardType, to, from2, runWithContext = (fn) => fn()) { + const guards = []; + for (const record of matched) { + for (const name in record.components) { + let rawComponent = record.components[name]; + if (guardType !== "beforeRouteEnter" && !record.instances[name]) continue; + if (isRouteComponent(rawComponent)) { + const guard = (rawComponent.__vccOpts || rawComponent)[guardType]; + guard && guards.push(guardToPromiseFn(guard, to, from2, record, name, runWithContext)); + } else { + let componentPromise = rawComponent(); + guards.push(() => componentPromise.then((resolved) => { + if (!resolved) throw new Error(`Couldn't resolve component "${name}" at "${record.path}"`); + const resolvedComponent = isESModule(resolved) ? resolved.default : resolved; + record.mods[name] = resolved; + record.components[name] = resolvedComponent; + const guard = (resolvedComponent.__vccOpts || resolvedComponent)[guardType]; + return guard && guardToPromiseFn(guard, to, from2, record, name, runWithContext)(); + })); + } + } + } + return guards; +} +function extractChangingRecords(to, from2) { + const leavingRecords = []; + const updatingRecords = []; + const enteringRecords = []; + const len = Math.max(from2.matched.length, to.matched.length); + for (let i = 0; i < len; i++) { + const recordFrom = from2.matched[i]; + if (recordFrom) if (to.matched.find((record) => isSameRouteRecord(record, recordFrom))) updatingRecords.push(recordFrom); + else leavingRecords.push(recordFrom); + const recordTo = to.matched[i]; + if (recordTo) { + if (!from2.matched.find((record) => isSameRouteRecord(record, recordTo))) enteringRecords.push(recordTo); + } + } + return [ + leavingRecords, + updatingRecords, + enteringRecords + ]; +} +let createBaseLocation = () => location.protocol + "//" + location.host; +function createCurrentLocation(base2, location2) { + const { pathname, search, hash } = location2; + const hashPos = base2.indexOf("#"); + if (hashPos > -1) { + let slicePos = hash.includes(base2.slice(hashPos)) ? base2.slice(hashPos).length : 1; + let pathFromHash = hash.slice(slicePos); + if (pathFromHash[0] !== "/") pathFromHash = "/" + pathFromHash; + return stripBase(pathFromHash, ""); + } + return stripBase(pathname, base2) + search + hash; +} +function useHistoryListeners(base2, historyState, currentLocation, replace2) { + let listeners = []; + let teardowns = []; + let pauseState = null; + const popStateHandler = ({ state }) => { + const to = createCurrentLocation(base2, location); + const from2 = currentLocation.value; + const fromState = historyState.value; + let delta = 0; + if (state) { + currentLocation.value = to; + historyState.value = state; + if (pauseState && pauseState === from2) { + pauseState = null; + return; + } + delta = fromState ? state.position - fromState.position : 0; + } else replace2(to); + listeners.forEach((listener) => { + listener(currentLocation.value, from2, { + delta, + type: NavigationType.pop, + direction: delta ? delta > 0 ? NavigationDirection.forward : NavigationDirection.back : NavigationDirection.unknown + }); + }); + }; + function pauseListeners() { + pauseState = currentLocation.value; + } + function listen(callback) { + listeners.push(callback); + const teardown = () => { + const index2 = listeners.indexOf(callback); + if (index2 > -1) listeners.splice(index2, 1); + }; + teardowns.push(teardown); + return teardown; + } + function beforeUnloadListener() { + if (document.visibilityState === "hidden") { + const { history: history2 } = window; + if (!history2.state) return; + history2.replaceState(assign$1({}, history2.state, { scroll: computeScrollPosition() }), ""); + } + } + function destroy() { + for (const teardown of teardowns) teardown(); + teardowns = []; + window.removeEventListener("popstate", popStateHandler); + window.removeEventListener("pagehide", beforeUnloadListener); + document.removeEventListener("visibilitychange", beforeUnloadListener); + } + window.addEventListener("popstate", popStateHandler); + window.addEventListener("pagehide", beforeUnloadListener); + document.addEventListener("visibilitychange", beforeUnloadListener); + return { + pauseListeners, + listen, + destroy + }; +} +function buildState(back, current, forward, replaced = false, computeScroll = false) { + return { + back, + current, + forward, + replaced, + position: window.history.length, + scroll: computeScroll ? computeScrollPosition() : null + }; +} +function useHistoryStateNavigation(base2) { + const { history: history2, location: location2 } = window; + const currentLocation = { value: createCurrentLocation(base2, location2) }; + const historyState = { value: history2.state }; + if (!historyState.value) changeLocation(currentLocation.value, { + back: null, + current: currentLocation.value, + forward: null, + position: history2.length - 1, + replaced: true, + scroll: null + }, true); + function changeLocation(to, state, replace22) { + const hashIndex = base2.indexOf("#"); + const url = hashIndex > -1 ? (location2.host && document.querySelector("base") ? base2 : base2.slice(hashIndex)) + to : createBaseLocation() + base2 + to; + try { + history2[replace22 ? "replaceState" : "pushState"](state, "", url); + historyState.value = state; + } catch (err) { + console.error(err); + location2[replace22 ? "replace" : "assign"](url); + } + } + function replace2(to, data) { + changeLocation(to, assign$1({}, history2.state, buildState(historyState.value.back, to, historyState.value.forward, true), data, { position: historyState.value.position }), true); + currentLocation.value = to; + } + function push(to, data) { + const currentState = assign$1({}, historyState.value, history2.state, { + forward: to, + scroll: computeScrollPosition() + }); + changeLocation(currentState.current, currentState, true); + changeLocation(to, assign$1({}, buildState(currentLocation.value, to, null), { position: currentState.position + 1 }, data), false); + currentLocation.value = to; + } + return { + location: currentLocation, + state: historyState, + push, + replace: replace2 + }; +} +function createWebHistory(base2) { + base2 = normalizeBase(base2); + const historyNavigation = useHistoryStateNavigation(base2); + const historyListeners = useHistoryListeners(base2, historyNavigation.state, historyNavigation.location, historyNavigation.replace); + function go(delta, triggerListeners = true) { + if (!triggerListeners) historyListeners.pauseListeners(); + history.go(delta); + } + const routerHistory = assign$1({ + location: "", + base: base2, + go, + createHref: createHref.bind(null, base2) + }, historyNavigation, historyListeners); + Object.defineProperty(routerHistory, "location", { + enumerable: true, + get: () => historyNavigation.location.value + }); + Object.defineProperty(routerHistory, "state", { + enumerable: true, + get: () => historyNavigation.state.value + }); + return routerHistory; +} +let TokenType = /* @__PURE__ */ (function(TokenType2) { + TokenType2[TokenType2["Static"] = 0] = "Static"; + TokenType2[TokenType2["Param"] = 1] = "Param"; + TokenType2[TokenType2["Group"] = 2] = "Group"; + return TokenType2; +})({}); +var TokenizerState = /* @__PURE__ */ (function(TokenizerState2) { + TokenizerState2[TokenizerState2["Static"] = 0] = "Static"; + TokenizerState2[TokenizerState2["Param"] = 1] = "Param"; + TokenizerState2[TokenizerState2["ParamRegExp"] = 2] = "ParamRegExp"; + TokenizerState2[TokenizerState2["ParamRegExpEnd"] = 3] = "ParamRegExpEnd"; + TokenizerState2[TokenizerState2["EscapeNext"] = 4] = "EscapeNext"; + return TokenizerState2; +})(TokenizerState || {}); +const ROOT_TOKEN = { + type: TokenType.Static, + value: "" +}; +const VALID_PARAM_RE = /[a-zA-Z0-9_]/; +function tokenizePath(path) { + if (!path) return [[]]; + if (path === "/") return [[ROOT_TOKEN]]; + if (!path.startsWith("/")) throw new Error(`Invalid path "${path}"`); + function crash(message) { + throw new Error(`ERR (${state})/"${buffer}": ${message}`); + } + let state = TokenizerState.Static; + let previousState = state; + const tokens = []; + let segment; + function finalizeSegment() { + if (segment) tokens.push(segment); + segment = []; + } + let i = 0; + let char; + let buffer = ""; + let customRe = ""; + function consumeBuffer() { + if (!buffer) return; + if (state === TokenizerState.Static) segment.push({ + type: TokenType.Static, + value: buffer + }); + else if (state === TokenizerState.Param || state === TokenizerState.ParamRegExp || state === TokenizerState.ParamRegExpEnd) { + if (segment.length > 1 && (char === "*" || char === "+")) crash(`A repeatable param (${buffer}) must be alone in its segment. eg: '/:ids+.`); + segment.push({ + type: TokenType.Param, + value: buffer, + regexp: customRe, + repeatable: char === "*" || char === "+", + optional: char === "*" || char === "?" + }); + } else crash("Invalid state to consume buffer"); + buffer = ""; + } + function addCharToBuffer() { + buffer += char; + } + while (i < path.length) { + char = path[i++]; + if (char === "\\" && state !== TokenizerState.ParamRegExp) { + previousState = state; + state = TokenizerState.EscapeNext; + continue; + } + switch (state) { + case TokenizerState.Static: + if (char === "/") { + if (buffer) consumeBuffer(); + finalizeSegment(); + } else if (char === ":") { + consumeBuffer(); + state = TokenizerState.Param; + } else addCharToBuffer(); + break; + case TokenizerState.EscapeNext: + addCharToBuffer(); + state = previousState; + break; + case TokenizerState.Param: + if (char === "(") state = TokenizerState.ParamRegExp; + else if (VALID_PARAM_RE.test(char)) addCharToBuffer(); + else { + consumeBuffer(); + state = TokenizerState.Static; + if (char !== "*" && char !== "?" && char !== "+") i--; + } + break; + case TokenizerState.ParamRegExp: + if (char === ")") if (customRe[customRe.length - 1] == "\\") customRe = customRe.slice(0, -1) + char; + else state = TokenizerState.ParamRegExpEnd; + else customRe += char; + break; + case TokenizerState.ParamRegExpEnd: + consumeBuffer(); + state = TokenizerState.Static; + if (char !== "*" && char !== "?" && char !== "+") i--; + customRe = ""; + break; + default: + crash("Unknown state"); + break; + } + } + if (state === TokenizerState.ParamRegExp) crash(`Unfinished custom RegExp for param "${buffer}"`); + consumeBuffer(); + finalizeSegment(); + return tokens; +} +const BASE_PARAM_PATTERN = "[^/]+?"; +const BASE_PATH_PARSER_OPTIONS = { + sensitive: false, + strict: false, + start: true, + end: true +}; +var PathScore = /* @__PURE__ */ (function(PathScore2) { + PathScore2[PathScore2["_multiplier"] = 10] = "_multiplier"; + PathScore2[PathScore2["Root"] = 90] = "Root"; + PathScore2[PathScore2["Segment"] = 40] = "Segment"; + PathScore2[PathScore2["SubSegment"] = 30] = "SubSegment"; + PathScore2[PathScore2["Static"] = 40] = "Static"; + PathScore2[PathScore2["Dynamic"] = 20] = "Dynamic"; + PathScore2[PathScore2["BonusCustomRegExp"] = 10] = "BonusCustomRegExp"; + PathScore2[PathScore2["BonusWildcard"] = -50] = "BonusWildcard"; + PathScore2[PathScore2["BonusRepeatable"] = -20] = "BonusRepeatable"; + PathScore2[PathScore2["BonusOptional"] = -8] = "BonusOptional"; + PathScore2[PathScore2["BonusStrict"] = 0.7000000000000001] = "BonusStrict"; + PathScore2[PathScore2["BonusCaseSensitive"] = 0.25] = "BonusCaseSensitive"; + return PathScore2; +})(PathScore || {}); +const REGEX_CHARS_RE = /[.+*?^${}()[\]/\\]/g; +function tokensToParser(segments, extraOptions) { + const options = assign$1({}, BASE_PATH_PARSER_OPTIONS, extraOptions); + const score = []; + let pattern = options.start ? "^" : ""; + const keys2 = []; + for (const segment of segments) { + const segmentScores = segment.length ? [] : [PathScore.Root]; + if (options.strict && !segment.length) pattern += "/"; + for (let tokenIndex = 0; tokenIndex < segment.length; tokenIndex++) { + const token2 = segment[tokenIndex]; + let subSegmentScore = PathScore.Segment + (options.sensitive ? PathScore.BonusCaseSensitive : 0); + if (token2.type === TokenType.Static) { + if (!tokenIndex) pattern += "/"; + pattern += token2.value.replace(REGEX_CHARS_RE, "\\$&"); + subSegmentScore += PathScore.Static; + } else if (token2.type === TokenType.Param) { + const { value, repeatable, optional, regexp } = token2; + keys2.push({ + name: value, + repeatable, + optional + }); + const re22 = regexp ? regexp : BASE_PARAM_PATTERN; + if (re22 !== BASE_PARAM_PATTERN) { + subSegmentScore += PathScore.BonusCustomRegExp; + try { + new RegExp(`(${re22})`); + } catch (err) { + throw new Error(`Invalid custom RegExp for param "${value}" (${re22}): ` + err.message); + } + } + let subPattern = repeatable ? `((?:${re22})(?:/(?:${re22}))*)` : `(${re22})`; + if (!tokenIndex) subPattern = optional && segment.length < 2 ? `(?:/${subPattern})` : "/" + subPattern; + if (optional) subPattern += "?"; + pattern += subPattern; + subSegmentScore += PathScore.Dynamic; + if (optional) subSegmentScore += PathScore.BonusOptional; + if (repeatable) subSegmentScore += PathScore.BonusRepeatable; + if (re22 === ".*") subSegmentScore += PathScore.BonusWildcard; + } + segmentScores.push(subSegmentScore); + } + score.push(segmentScores); + } + if (options.strict && options.end) { + const i = score.length - 1; + score[i][score[i].length - 1] += PathScore.BonusStrict; + } + if (!options.strict) pattern += "/?"; + if (options.end) pattern += "$"; + else if (options.strict && !pattern.endsWith("/")) pattern += "(?:/|$)"; + const re2 = new RegExp(pattern, options.sensitive ? "" : "i"); + function parse(path) { + const match = path.match(re2); + const params = {}; + if (!match) return null; + for (let i = 1; i < match.length; i++) { + const value = match[i] || ""; + const key = keys2[i - 1]; + params[key.name] = value && key.repeatable ? value.split("/") : value; + } + return params; + } + function stringify(params) { + let path = ""; + let avoidDuplicatedSlash = false; + for (const segment of segments) { + if (!avoidDuplicatedSlash || !path.endsWith("/")) path += "/"; + avoidDuplicatedSlash = false; + for (const token2 of segment) if (token2.type === TokenType.Static) path += token2.value; + else if (token2.type === TokenType.Param) { + const { value, repeatable, optional } = token2; + const param = value in params ? params[value] : ""; + if (isArray(param) && !repeatable) throw new Error(`Provided param "${value}" is an array but it is not repeatable (* or + modifiers)`); + const text = isArray(param) ? param.join("/") : param; + if (!text) if (optional) { + if (segment.length < 2) if (path.endsWith("/")) path = path.slice(0, -1); + else avoidDuplicatedSlash = true; + } else throw new Error(`Missing required param "${value}"`); + path += text; + } + } + return path || "/"; + } + return { + re: re2, + score, + keys: keys2, + parse, + stringify + }; +} +function compareScoreArray(a, b2) { + let i = 0; + while (i < a.length && i < b2.length) { + const diff = b2[i] - a[i]; + if (diff) return diff; + i++; + } + if (a.length < b2.length) return a.length === 1 && a[0] === PathScore.Static + PathScore.Segment ? -1 : 1; + else if (a.length > b2.length) return b2.length === 1 && b2[0] === PathScore.Static + PathScore.Segment ? 1 : -1; + return 0; +} +function comparePathParserScore(a, b2) { + let i = 0; + const aScore = a.score; + const bScore = b2.score; + while (i < aScore.length && i < bScore.length) { + const comp = compareScoreArray(aScore[i], bScore[i]); + if (comp) return comp; + i++; + } + if (Math.abs(bScore.length - aScore.length) === 1) { + if (isLastScoreNegative(aScore)) return 1; + if (isLastScoreNegative(bScore)) return -1; + } + return bScore.length - aScore.length; +} +function isLastScoreNegative(score) { + const last = score[score.length - 1]; + return score.length > 0 && last[last.length - 1] < 0; +} +const PATH_PARSER_OPTIONS_DEFAULTS = { + strict: false, + end: true, + sensitive: false +}; +function createRouteRecordMatcher(record, parent, options) { + const parser = tokensToParser(tokenizePath(record.path), options); + const matcher = assign$1(parser, { + record, + parent, + children: [], + alias: [] + }); + if (parent) { + if (!matcher.record.aliasOf === !parent.record.aliasOf) parent.children.push(matcher); + } + return matcher; +} +function createRouterMatcher(routes2, globalOptions) { + const matchers = []; + const matcherMap = /* @__PURE__ */ new Map(); + globalOptions = mergeOptions(PATH_PARSER_OPTIONS_DEFAULTS, globalOptions); + function getRecordMatcher(name) { + return matcherMap.get(name); + } + function addRoute(record, parent, originalRecord) { + const isRootAdd = !originalRecord; + const mainNormalizedRecord = normalizeRouteRecord(record); + mainNormalizedRecord.aliasOf = originalRecord && originalRecord.record; + const options = mergeOptions(globalOptions, record); + const normalizedRecords = [mainNormalizedRecord]; + if ("alias" in record) { + const aliases = typeof record.alias === "string" ? [record.alias] : record.alias; + for (const alias of aliases) normalizedRecords.push(normalizeRouteRecord(assign$1({}, mainNormalizedRecord, { + components: originalRecord ? originalRecord.record.components : mainNormalizedRecord.components, + path: alias, + aliasOf: originalRecord ? originalRecord.record : mainNormalizedRecord + }))); + } + let matcher; + let originalMatcher; + for (const normalizedRecord of normalizedRecords) { + const { path } = normalizedRecord; + if (parent && path[0] !== "/") { + const parentPath = parent.record.path; + const connectingSlash = parentPath[parentPath.length - 1] === "/" ? "" : "/"; + normalizedRecord.path = parent.record.path + (path && connectingSlash + path); + } + matcher = createRouteRecordMatcher(normalizedRecord, parent, options); + if (originalRecord) { + originalRecord.alias.push(matcher); + } else { + originalMatcher = originalMatcher || matcher; + if (originalMatcher !== matcher) originalMatcher.alias.push(matcher); + if (isRootAdd && record.name && !isAliasRecord(matcher)) { + removeRoute(record.name); + } + } + if (isMatchable(matcher)) insertMatcher(matcher); + if (mainNormalizedRecord.children) { + const children = mainNormalizedRecord.children; + for (let i = 0; i < children.length; i++) addRoute(children[i], matcher, originalRecord && originalRecord.children[i]); + } + originalRecord = originalRecord || matcher; + } + return originalMatcher ? () => { + removeRoute(originalMatcher); + } : noop$1; + } + function removeRoute(matcherRef) { + if (isRouteName(matcherRef)) { + const matcher = matcherMap.get(matcherRef); + if (matcher) { + matcherMap.delete(matcherRef); + matchers.splice(matchers.indexOf(matcher), 1); + matcher.children.forEach(removeRoute); + matcher.alias.forEach(removeRoute); + } + } else { + const index2 = matchers.indexOf(matcherRef); + if (index2 > -1) { + matchers.splice(index2, 1); + if (matcherRef.record.name) matcherMap.delete(matcherRef.record.name); + matcherRef.children.forEach(removeRoute); + matcherRef.alias.forEach(removeRoute); + } + } + } + function getRoutes() { + return matchers; + } + function insertMatcher(matcher) { + const index2 = findInsertionIndex(matcher, matchers); + matchers.splice(index2, 0, matcher); + if (matcher.record.name && !isAliasRecord(matcher)) matcherMap.set(matcher.record.name, matcher); + } + function resolve2(location2, currentLocation) { + let matcher; + let params = {}; + let path; + let name; + if ("name" in location2 && location2.name) { + matcher = matcherMap.get(location2.name); + if (!matcher) throw createRouterError(ErrorTypes.MATCHER_NOT_FOUND, { location: location2 }); + name = matcher.record.name; + params = assign$1(pickParams(currentLocation.params, matcher.keys.filter((k2) => !k2.optional).concat(matcher.parent ? matcher.parent.keys.filter((k2) => k2.optional) : []).map((k2) => k2.name)), location2.params && pickParams(location2.params, matcher.keys.map((k2) => k2.name))); + path = matcher.stringify(params); + } else if (location2.path != null) { + path = location2.path; + matcher = matchers.find((m2) => m2.re.test(path)); + if (matcher) { + params = matcher.parse(path); + name = matcher.record.name; + } + } else { + matcher = currentLocation.name ? matcherMap.get(currentLocation.name) : matchers.find((m2) => m2.re.test(currentLocation.path)); + if (!matcher) throw createRouterError(ErrorTypes.MATCHER_NOT_FOUND, { + location: location2, + currentLocation + }); + name = matcher.record.name; + params = assign$1({}, currentLocation.params, location2.params); + path = matcher.stringify(params); + } + const matched = []; + let parentMatcher = matcher; + while (parentMatcher) { + matched.unshift(parentMatcher.record); + parentMatcher = parentMatcher.parent; + } + return { + name, + path, + params, + matched, + meta: mergeMetaFields(matched) + }; + } + routes2.forEach((route) => addRoute(route)); + function clearRoutes() { + matchers.length = 0; + matcherMap.clear(); + } + return { + addRoute, + resolve: resolve2, + removeRoute, + clearRoutes, + getRoutes, + getRecordMatcher + }; +} +function pickParams(params, keys2) { + const newParams = {}; + for (const key of keys2) if (key in params) newParams[key] = params[key]; + return newParams; +} +function normalizeRouteRecord(record) { + const normalized = { + path: record.path, + redirect: record.redirect, + name: record.name, + meta: record.meta || {}, + aliasOf: record.aliasOf, + beforeEnter: record.beforeEnter, + props: normalizeRecordProps(record), + children: record.children || [], + instances: {}, + leaveGuards: /* @__PURE__ */ new Set(), + updateGuards: /* @__PURE__ */ new Set(), + enterCallbacks: {}, + components: "components" in record ? record.components || null : record.component && { default: record.component } + }; + Object.defineProperty(normalized, "mods", { value: {} }); + return normalized; +} +function normalizeRecordProps(record) { + const propsObject = {}; + const props = record.props || false; + if ("component" in record) propsObject.default = props; + else for (const name in record.components) propsObject[name] = typeof props === "object" ? props[name] : props; + return propsObject; +} +function isAliasRecord(record) { + while (record) { + if (record.record.aliasOf) return true; + record = record.parent; + } + return false; +} +function mergeMetaFields(matched) { + return matched.reduce((meta, record) => assign$1(meta, record.meta), {}); +} +function findInsertionIndex(matcher, matchers) { + let lower = 0; + let upper = matchers.length; + while (lower !== upper) { + const mid = lower + upper >> 1; + if (comparePathParserScore(matcher, matchers[mid]) < 0) upper = mid; + else lower = mid + 1; + } + const insertionAncestor = getInsertionAncestor(matcher); + if (insertionAncestor) { + upper = matchers.lastIndexOf(insertionAncestor, upper - 1); + } + return upper; +} +function getInsertionAncestor(matcher) { + let ancestor = matcher; + while (ancestor = ancestor.parent) if (isMatchable(ancestor) && comparePathParserScore(matcher, ancestor) === 0) return ancestor; +} +function isMatchable({ record }) { + return !!(record.name || record.components && Object.keys(record.components).length || record.redirect); +} +function useLink(props) { + const router2 = inject(routerKey); + const currentRoute = inject(routeLocationKey); + const route = computed(() => { + const to = unref(props.to); + return router2.resolve(to); + }); + const activeRecordIndex = computed(() => { + const { matched } = route.value; + const { length } = matched; + const routeMatched = matched[length - 1]; + const currentMatched = currentRoute.matched; + if (!routeMatched || !currentMatched.length) return -1; + const index2 = currentMatched.findIndex(isSameRouteRecord.bind(null, routeMatched)); + if (index2 > -1) return index2; + const parentRecordPath = getOriginalPath(matched[length - 2]); + return length > 1 && getOriginalPath(routeMatched) === parentRecordPath && currentMatched[currentMatched.length - 1].path !== parentRecordPath ? currentMatched.findIndex(isSameRouteRecord.bind(null, matched[length - 2])) : index2; + }); + const isActive2 = computed(() => activeRecordIndex.value > -1 && includesParams(currentRoute.params, route.value.params)); + const isExactActive = computed(() => activeRecordIndex.value > -1 && activeRecordIndex.value === currentRoute.matched.length - 1 && isSameRouteLocationParams(currentRoute.params, route.value.params)); + function navigate(e = {}) { + if (guardEvent(e)) { + const p2 = router2[unref(props.replace) ? "replace" : "push"](unref(props.to)).catch(noop$1); + if (props.viewTransition && typeof document !== "undefined" && "startViewTransition" in document) document.startViewTransition(() => p2); + return p2; + } + return Promise.resolve(); + } + return { + route, + href: computed(() => route.value.href), + isActive: isActive2, + isExactActive, + navigate + }; +} +function preferSingleVNode(vnodes) { + return vnodes.length === 1 ? vnodes[0] : vnodes; +} +const RouterLinkImpl = /* @__PURE__ */ defineComponent({ + name: "RouterLink", + compatConfig: { MODE: 3 }, + props: { + to: { + type: [String, Object], + required: true + }, + replace: Boolean, + activeClass: String, + exactActiveClass: String, + custom: Boolean, + ariaCurrentValue: { + type: String, + default: "page" + }, + viewTransition: Boolean + }, + useLink, + setup(props, { slots }) { + const link = /* @__PURE__ */ reactive(useLink(props)); + const { options } = inject(routerKey); + const elClass = computed(() => ({ + [getLinkClass(props.activeClass, options.linkActiveClass, "router-link-active")]: link.isActive, + [getLinkClass(props.exactActiveClass, options.linkExactActiveClass, "router-link-exact-active")]: link.isExactActive + })); + return () => { + const children = slots.default && preferSingleVNode(slots.default(link)); + return props.custom ? children : h$1("a", { + "aria-current": link.isExactActive ? props.ariaCurrentValue : null, + href: link.href, + onClick: link.navigate, + class: elClass.value + }, children); + }; + } +}); +const RouterLink = RouterLinkImpl; +function guardEvent(e) { + if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return; + if (e.defaultPrevented) return; + if (e.button !== void 0 && e.button !== 0) return; + if (e.currentTarget && e.currentTarget.getAttribute) { + const target = e.currentTarget.getAttribute("target"); + if (/\b_blank\b/i.test(target)) return; + } + if (e.preventDefault) e.preventDefault(); + return true; +} +function includesParams(outer, inner) { + for (const key in inner) { + const innerValue = inner[key]; + const outerValue = outer[key]; + if (typeof innerValue === "string") { + if (innerValue !== outerValue) return false; + } else if (!isArray(outerValue) || outerValue.length !== innerValue.length || innerValue.some((value, i) => value.valueOf() !== outerValue[i].valueOf())) return false; + } + return true; +} +function getOriginalPath(record) { + return record ? record.aliasOf ? record.aliasOf.path : record.path : ""; +} +const getLinkClass = (propClass, globalClass, defaultClass) => propClass != null ? propClass : globalClass != null ? globalClass : defaultClass; +const RouterViewImpl = /* @__PURE__ */ defineComponent({ + name: "RouterView", + inheritAttrs: false, + props: { + name: { + type: String, + default: "default" + }, + route: Object + }, + compatConfig: { MODE: 3 }, + setup(props, { attrs, slots }) { + const injectedRoute = inject(routerViewLocationKey); + const routeToDisplay = computed(() => props.route || injectedRoute.value); + const injectedDepth = inject(viewDepthKey, 0); + const depth = computed(() => { + let initialDepth = unref(injectedDepth); + const { matched } = routeToDisplay.value; + let matchedRoute; + while ((matchedRoute = matched[initialDepth]) && !matchedRoute.components) initialDepth++; + return initialDepth; + }); + const matchedRouteRef = computed(() => routeToDisplay.value.matched[depth.value]); + provide(viewDepthKey, computed(() => depth.value + 1)); + provide(matchedRouteKey, matchedRouteRef); + provide(routerViewLocationKey, routeToDisplay); + const viewRef = /* @__PURE__ */ ref(); + watch(() => [ + viewRef.value, + matchedRouteRef.value, + props.name + ], ([instance, to, name], [oldInstance, from2, oldName]) => { + if (to) { + to.instances[name] = instance; + if (from2 && from2 !== to && instance && instance === oldInstance) { + if (!to.leaveGuards.size) to.leaveGuards = from2.leaveGuards; + if (!to.updateGuards.size) to.updateGuards = from2.updateGuards; + } + } + if (instance && to && (!from2 || !isSameRouteRecord(to, from2) || !oldInstance)) (to.enterCallbacks[name] || []).forEach((callback) => callback(instance)); + }, { flush: "post" }); + return () => { + const route = routeToDisplay.value; + const currentName = props.name; + const matchedRoute = matchedRouteRef.value; + const ViewComponent = matchedRoute && matchedRoute.components[currentName]; + if (!ViewComponent) return normalizeSlot(slots.default, { + Component: ViewComponent, + route + }); + const routePropsOption = matchedRoute.props[currentName]; + const routeProps = routePropsOption ? routePropsOption === true ? route.params : typeof routePropsOption === "function" ? routePropsOption(route) : routePropsOption : null; + const onVnodeUnmounted = (vnode) => { + if (vnode.component.isUnmounted) matchedRoute.instances[currentName] = null; + }; + const component = h$1(ViewComponent, assign$1({}, routeProps, attrs, { + onVnodeUnmounted, + ref: viewRef + })); + return normalizeSlot(slots.default, { + Component: component, + route + }) || component; + }; + } +}); +function normalizeSlot(slot, data) { + if (!slot) return null; + const slotContent = slot(data); + return slotContent.length === 1 ? slotContent[0] : slotContent; +} +const RouterView = RouterViewImpl; +function createRouter(options) { + const matcher = createRouterMatcher(options.routes, options); + const parseQuery$1 = options.parseQuery || parseQuery; + const stringifyQuery$1 = options.stringifyQuery || stringifyQuery; + const routerHistory = options.history; + const beforeGuards = useCallbacks(); + const beforeResolveGuards = useCallbacks(); + const afterGuards = useCallbacks(); + const currentRoute = /* @__PURE__ */ shallowRef(START_LOCATION_NORMALIZED); + let pendingLocation = START_LOCATION_NORMALIZED; + if (isBrowser && options.scrollBehavior && "scrollRestoration" in history) history.scrollRestoration = "manual"; + const normalizeParams = applyToParams.bind(null, (paramValue) => "" + paramValue); + const encodeParams = applyToParams.bind(null, encodeParam); + const decodeParams = applyToParams.bind(null, decode); + function addRoute(parentOrRoute, route) { + let parent; + let record; + if (isRouteName(parentOrRoute)) { + parent = matcher.getRecordMatcher(parentOrRoute); + record = route; + } else record = parentOrRoute; + return matcher.addRoute(record, parent); + } + function removeRoute(name) { + const recordMatcher = matcher.getRecordMatcher(name); + if (recordMatcher) matcher.removeRoute(recordMatcher); + } + function getRoutes() { + return matcher.getRoutes().map((routeMatcher) => routeMatcher.record); + } + function hasRoute(name) { + return !!matcher.getRecordMatcher(name); + } + function resolve2(rawLocation, currentLocation) { + currentLocation = assign$1({}, currentLocation || currentRoute.value); + if (typeof rawLocation === "string") { + const locationNormalized = parseURL(parseQuery$1, rawLocation, currentLocation.path); + const matchedRoute2 = matcher.resolve({ path: locationNormalized.path }, currentLocation); + const href2 = routerHistory.createHref(locationNormalized.fullPath); + return assign$1(locationNormalized, matchedRoute2, { + params: decodeParams(matchedRoute2.params), + hash: decode(locationNormalized.hash), + redirectedFrom: void 0, + href: href2 + }); + } + let matcherLocation; + if (rawLocation.path != null) { + matcherLocation = assign$1({}, rawLocation, { path: parseURL(parseQuery$1, rawLocation.path, currentLocation.path).path }); + } else { + const targetParams = assign$1({}, rawLocation.params); + for (const key in targetParams) if (targetParams[key] == null) delete targetParams[key]; + matcherLocation = assign$1({}, rawLocation, { params: encodeParams(targetParams) }); + currentLocation.params = encodeParams(currentLocation.params); + } + const matchedRoute = matcher.resolve(matcherLocation, currentLocation); + const hash = rawLocation.hash || ""; + matchedRoute.params = normalizeParams(decodeParams(matchedRoute.params)); + const fullPath = stringifyURL(stringifyQuery$1, assign$1({}, rawLocation, { + hash: encodeHash(hash), + path: matchedRoute.path + })); + const href = routerHistory.createHref(fullPath); + return assign$1({ + fullPath, + hash, + query: stringifyQuery$1 === stringifyQuery ? normalizeQuery(rawLocation.query) : rawLocation.query || {} + }, matchedRoute, { + redirectedFrom: void 0, + href + }); + } + function locationAsObject(to) { + return typeof to === "string" ? parseURL(parseQuery$1, to, currentRoute.value.path) : assign$1({}, to); + } + function checkCanceledNavigation(to, from2) { + if (pendingLocation !== to) return createRouterError(ErrorTypes.NAVIGATION_CANCELLED, { + from: from2, + to + }); + } + function push(to) { + return pushWithRedirect(to); + } + function replace2(to) { + return push(assign$1(locationAsObject(to), { replace: true })); + } + function handleRedirectRecord(to, from2) { + const lastMatched = to.matched[to.matched.length - 1]; + if (lastMatched && lastMatched.redirect) { + const { redirect } = lastMatched; + let newTargetLocation = typeof redirect === "function" ? redirect(to, from2) : redirect; + if (typeof newTargetLocation === "string") { + newTargetLocation = newTargetLocation.includes("?") || newTargetLocation.includes("#") ? newTargetLocation = locationAsObject(newTargetLocation) : { path: newTargetLocation }; + newTargetLocation.params = {}; + } + return assign$1({ + query: to.query, + hash: to.hash, + params: newTargetLocation.path != null ? {} : to.params + }, newTargetLocation); + } + } + function pushWithRedirect(to, redirectedFrom) { + const targetLocation = pendingLocation = resolve2(to); + const from2 = currentRoute.value; + const data = to.state; + const force = to.force; + const replace22 = to.replace === true; + const shouldRedirect = handleRedirectRecord(targetLocation, from2); + if (shouldRedirect) return pushWithRedirect(assign$1(locationAsObject(shouldRedirect), { + state: typeof shouldRedirect === "object" ? assign$1({}, data, shouldRedirect.state) : data, + force, + replace: replace22 + }), redirectedFrom || targetLocation); + const toLocation = targetLocation; + toLocation.redirectedFrom = redirectedFrom; + let failure; + if (!force && isSameRouteLocation(stringifyQuery$1, from2, targetLocation)) { + failure = createRouterError(ErrorTypes.NAVIGATION_DUPLICATED, { + to: toLocation, + from: from2 + }); + handleScroll(from2, from2, true, false); + } + return (failure ? Promise.resolve(failure) : navigate(toLocation, from2)).catch((error) => isNavigationFailure(error) ? isNavigationFailure(error, ErrorTypes.NAVIGATION_GUARD_REDIRECT) ? error : markAsReady(error) : triggerError(error, toLocation, from2)).then((failure2) => { + if (failure2) { + if (isNavigationFailure(failure2, ErrorTypes.NAVIGATION_GUARD_REDIRECT)) { + return pushWithRedirect(assign$1({ replace: replace22 }, locationAsObject(failure2.to), { + state: typeof failure2.to === "object" ? assign$1({}, data, failure2.to.state) : data, + force + }), redirectedFrom || toLocation); + } + } else failure2 = finalizeNavigation(toLocation, from2, true, replace22, data); + triggerAfterEach(toLocation, from2, failure2); + return failure2; + }); + } + function checkCanceledNavigationAndReject(to, from2) { + const error = checkCanceledNavigation(to, from2); + return error ? Promise.reject(error) : Promise.resolve(); + } + function runWithContext(fn) { + const app2 = installedApps.values().next().value; + return app2 && typeof app2.runWithContext === "function" ? app2.runWithContext(fn) : fn(); + } + function navigate(to, from2) { + let guards; + const [leavingRecords, updatingRecords, enteringRecords] = extractChangingRecords(to, from2); + guards = extractComponentsGuards(leavingRecords.reverse(), "beforeRouteLeave", to, from2); + for (const record of leavingRecords) record.leaveGuards.forEach((guard) => { + guards.push(guardToPromiseFn(guard, to, from2)); + }); + const canceledNavigationCheck = checkCanceledNavigationAndReject.bind(null, to, from2); + guards.push(canceledNavigationCheck); + return runGuardQueue(guards).then(() => { + guards = []; + for (const guard of beforeGuards.list()) guards.push(guardToPromiseFn(guard, to, from2)); + guards.push(canceledNavigationCheck); + return runGuardQueue(guards); + }).then(() => { + guards = extractComponentsGuards(updatingRecords, "beforeRouteUpdate", to, from2); + for (const record of updatingRecords) record.updateGuards.forEach((guard) => { + guards.push(guardToPromiseFn(guard, to, from2)); + }); + guards.push(canceledNavigationCheck); + return runGuardQueue(guards); + }).then(() => { + guards = []; + for (const record of enteringRecords) if (record.beforeEnter) if (isArray(record.beforeEnter)) for (const beforeEnter of record.beforeEnter) guards.push(guardToPromiseFn(beforeEnter, to, from2)); + else guards.push(guardToPromiseFn(record.beforeEnter, to, from2)); + guards.push(canceledNavigationCheck); + return runGuardQueue(guards); + }).then(() => { + to.matched.forEach((record) => record.enterCallbacks = {}); + guards = extractComponentsGuards(enteringRecords, "beforeRouteEnter", to, from2, runWithContext); + guards.push(canceledNavigationCheck); + return runGuardQueue(guards); + }).then(() => { + guards = []; + for (const guard of beforeResolveGuards.list()) guards.push(guardToPromiseFn(guard, to, from2)); + guards.push(canceledNavigationCheck); + return runGuardQueue(guards); + }).catch((err) => isNavigationFailure(err, ErrorTypes.NAVIGATION_CANCELLED) ? err : Promise.reject(err)); + } + function triggerAfterEach(to, from2, failure) { + afterGuards.list().forEach((guard) => runWithContext(() => guard(to, from2, failure))); + } + function finalizeNavigation(toLocation, from2, isPush, replace22, data) { + const error = checkCanceledNavigation(toLocation, from2); + if (error) return error; + const isFirstNavigation = from2 === START_LOCATION_NORMALIZED; + const state = !isBrowser ? {} : history.state; + if (isPush) if (replace22 || isFirstNavigation) routerHistory.replace(toLocation.fullPath, assign$1({ scroll: isFirstNavigation && state && state.scroll }, data)); + else routerHistory.push(toLocation.fullPath, data); + currentRoute.value = toLocation; + handleScroll(toLocation, from2, isPush, isFirstNavigation); + markAsReady(); + } + let removeHistoryListener; + function setupListeners() { + if (removeHistoryListener) return; + removeHistoryListener = routerHistory.listen((to, _from, info) => { + if (!router2.listening) return; + const toLocation = resolve2(to); + const shouldRedirect = handleRedirectRecord(toLocation, router2.currentRoute.value); + if (shouldRedirect) { + pushWithRedirect(assign$1(shouldRedirect, { + replace: true, + force: true + }), toLocation).catch(noop$1); + return; + } + pendingLocation = toLocation; + const from2 = currentRoute.value; + if (isBrowser) saveScrollPosition(getScrollKey(from2.fullPath, info.delta), computeScrollPosition()); + navigate(toLocation, from2).catch((error) => { + if (isNavigationFailure(error, ErrorTypes.NAVIGATION_ABORTED | ErrorTypes.NAVIGATION_CANCELLED)) return error; + if (isNavigationFailure(error, ErrorTypes.NAVIGATION_GUARD_REDIRECT)) { + pushWithRedirect(assign$1(locationAsObject(error.to), { force: true }), toLocation).then((failure) => { + if (isNavigationFailure(failure, ErrorTypes.NAVIGATION_ABORTED | ErrorTypes.NAVIGATION_DUPLICATED) && !info.delta && info.type === NavigationType.pop) routerHistory.go(-1, false); + }).catch(noop$1); + return Promise.reject(); + } + if (info.delta) routerHistory.go(-info.delta, false); + return triggerError(error, toLocation, from2); + }).then((failure) => { + failure = failure || finalizeNavigation(toLocation, from2, false); + if (failure) { + if (info.delta && !isNavigationFailure(failure, ErrorTypes.NAVIGATION_CANCELLED)) routerHistory.go(-info.delta, false); + else if (info.type === NavigationType.pop && isNavigationFailure(failure, ErrorTypes.NAVIGATION_ABORTED | ErrorTypes.NAVIGATION_DUPLICATED)) routerHistory.go(-1, false); + } + triggerAfterEach(toLocation, from2, failure); + }).catch(noop$1); + }); + } + let readyHandlers = useCallbacks(); + let errorListeners = useCallbacks(); + let ready; + function triggerError(error, to, from2) { + markAsReady(error); + const list = errorListeners.list(); + if (list.length) list.forEach((handler) => handler(error, to, from2)); + else { + console.error(error); + } + return Promise.reject(error); + } + function isReady() { + if (ready && currentRoute.value !== START_LOCATION_NORMALIZED) return Promise.resolve(); + return new Promise((resolve22, reject) => { + readyHandlers.add([resolve22, reject]); + }); + } + function markAsReady(err) { + if (!ready) { + ready = !err; + setupListeners(); + readyHandlers.list().forEach(([resolve22, reject]) => err ? reject(err) : resolve22()); + readyHandlers.reset(); + } + return err; + } + function handleScroll(to, from2, isPush, isFirstNavigation) { + const { scrollBehavior } = options; + if (!isBrowser || !scrollBehavior) return Promise.resolve(); + const scrollPosition = !isPush && getSavedScrollPosition(getScrollKey(to.fullPath, 0)) || (isFirstNavigation || !isPush) && history.state && history.state.scroll || null; + return nextTick().then(() => scrollBehavior(to, from2, scrollPosition)).then((position) => position && scrollToPosition(position)).catch((err) => triggerError(err, to, from2)); + } + const go = (delta) => routerHistory.go(delta); + let started; + const installedApps = /* @__PURE__ */ new Set(); + const router2 = { + currentRoute, + listening: true, + addRoute, + removeRoute, + clearRoutes: matcher.clearRoutes, + hasRoute, + getRoutes, + resolve: resolve2, + options, + push, + replace: replace2, + go, + back: () => go(-1), + forward: () => go(1), + beforeEach: beforeGuards.add, + beforeResolve: beforeResolveGuards.add, + afterEach: afterGuards.add, + onError: errorListeners.add, + isReady, + install(app2) { + app2.component("RouterLink", RouterLink); + app2.component("RouterView", RouterView); + app2.config.globalProperties.$router = router2; + Object.defineProperty(app2.config.globalProperties, "$route", { + enumerable: true, + get: () => unref(currentRoute) + }); + if (isBrowser && !started && currentRoute.value === START_LOCATION_NORMALIZED) { + started = true; + push(routerHistory.location).catch((err) => { + }); + } + const reactiveRoute = {}; + for (const key in START_LOCATION_NORMALIZED) Object.defineProperty(reactiveRoute, key, { + get: () => currentRoute.value[key], + enumerable: true + }); + app2.provide(routerKey, router2); + app2.provide(routeLocationKey, /* @__PURE__ */ shallowReactive(reactiveRoute)); + app2.provide(routerViewLocationKey, currentRoute); + const unmountApp = app2.unmount; + installedApps.add(app2); + app2.unmount = function() { + installedApps.delete(app2); + if (installedApps.size < 1) { + pendingLocation = START_LOCATION_NORMALIZED; + removeHistoryListener && removeHistoryListener(); + removeHistoryListener = null; + currentRoute.value = START_LOCATION_NORMALIZED; + started = false; + ready = false; + } + unmountApp(); + }; + } + }; + function runGuardQueue(guards) { + return guards.reduce((promise, guard) => promise.then(() => runWithContext(guard)), Promise.resolve()); + } + return router2; +} +const categories = /* @__PURE__ */ ref([]); +const searchResults = /* @__PURE__ */ ref([]); +const useNotes = () => { + async function loadCategories() { + categories.value = await window.notesAPI.call("getCategories"); + } + async function loadCategoryNotes(category = null) { + return await window.notesAPI.call("getCategoryNotes", category); + } + async function loadNote(id) { + return await window.notesAPI.call("getNote", id); + } + async function createNote(metadata, content) { + const note = await window.notesAPI.call("createNote", metadata, content); + await loadCategories(); + return note; + } + async function updateNoteContent(id, content) { + const note = await window.notesAPI.call("updateNote", id, content); + return note; + } + async function updateNoteMetadata(id, updates) { + const note = await window.notesAPI.call( + "updateNoteMetadata", + id, + updates + ); + await loadCategories(); + return note; + } + async function search(query) { + if (!query) { + searchResults.value = []; + return; + } + searchResults.value = await window.notesAPI.call("search", query); + } + return { + categories, + searchResults, + loadCategories, + loadCategoryNotes, + loadNote, + createNote, + updateNoteContent, + updateNoteMetadata, + search + }; +}; +const _hoisted_1$4 = { class: "index" }; +const _hoisted_2$4 = { class: "title h1" }; +const _sfc_main$4 = { + __name: "CategoryRow", + props: { index: Number, category: String }, + setup(__props) { + return (_ctx, _cache) => { + const _component_router_link = resolveComponent("router-link"); + return openBlock(), createBlock(_component_router_link, { + class: "category-row", + to: `/category/${__props.category}` + }, { + default: withCtx(() => [ + createBaseVNode("span", _hoisted_1$4, toDisplayString(String(__props.index + 1).padStart(2, "0")) + ".", 1), + createBaseVNode("span", _hoisted_2$4, toDisplayString(__props.category), 1) + ]), + _: 1 + }, 8, ["to"]); + }; + } +}; +const useOpenNote = () => { + const router2 = useRouter(); + function openNote(noteId, options = {}) { + const { newWindow = true } = options; + const isElectron = typeof window !== "undefined" && window.api && typeof window.api.openNoteWindow === "function"; + if (newWindow && isElectron) { + window.api.openNoteWindow(noteId); + return; + } + router2.push(`/note/${noteId}`); + } + return { + openNote + }; +}; +var token = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|Z|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g; +var literal = /\[([^]*?)\]/gm; +function shorten(arr, sLen) { + var newArr = []; + for (var i = 0, len = arr.length; i < len; i++) { + newArr.push(arr[i].substr(0, sLen)); + } + return newArr; +} +function assign(origObj) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + for (var _a = 0, args_1 = args; _a < args_1.length; _a++) { + var obj = args_1[_a]; + for (var key in obj) { + origObj[key] = obj[key]; + } + } + return origObj; +} +var dayNames = [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" +]; +var monthNames = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December" +]; +var monthNamesShort = shorten(monthNames, 3); +var dayNamesShort = shorten(dayNames, 3); +var defaultI18n = { + dayNamesShort, + dayNames, + monthNamesShort, + monthNames, + amPm: ["am", "pm"], + DoFn: function(dayOfMonth) { + return dayOfMonth + ["th", "st", "nd", "rd"][dayOfMonth % 10 > 3 ? 0 : (dayOfMonth - dayOfMonth % 10 !== 10 ? 1 : 0) * dayOfMonth % 10]; + } +}; +var globalI18n = assign({}, defaultI18n); +var pad = function(val, len) { + if (len === void 0) { + len = 2; + } + val = String(val); + while (val.length < len) { + val = "0" + val; + } + return val; +}; +var formatFlags = { + D: function(dateObj) { + return String(dateObj.getDate()); + }, + DD: function(dateObj) { + return pad(dateObj.getDate()); + }, + Do: function(dateObj, i18n) { + return i18n.DoFn(dateObj.getDate()); + }, + d: function(dateObj) { + return String(dateObj.getDay()); + }, + dd: function(dateObj) { + return pad(dateObj.getDay()); + }, + ddd: function(dateObj, i18n) { + return i18n.dayNamesShort[dateObj.getDay()]; + }, + dddd: function(dateObj, i18n) { + return i18n.dayNames[dateObj.getDay()]; + }, + M: function(dateObj) { + return String(dateObj.getMonth() + 1); + }, + MM: function(dateObj) { + return pad(dateObj.getMonth() + 1); + }, + MMM: function(dateObj, i18n) { + return i18n.monthNamesShort[dateObj.getMonth()]; + }, + MMMM: function(dateObj, i18n) { + return i18n.monthNames[dateObj.getMonth()]; + }, + YY: function(dateObj) { + return pad(String(dateObj.getFullYear()), 4).substr(2); + }, + YYYY: function(dateObj) { + return pad(dateObj.getFullYear(), 4); + }, + h: function(dateObj) { + return String(dateObj.getHours() % 12 || 12); + }, + hh: function(dateObj) { + return pad(dateObj.getHours() % 12 || 12); + }, + H: function(dateObj) { + return String(dateObj.getHours()); + }, + HH: function(dateObj) { + return pad(dateObj.getHours()); + }, + m: function(dateObj) { + return String(dateObj.getMinutes()); + }, + mm: function(dateObj) { + return pad(dateObj.getMinutes()); + }, + s: function(dateObj) { + return String(dateObj.getSeconds()); + }, + ss: function(dateObj) { + return pad(dateObj.getSeconds()); + }, + S: function(dateObj) { + return String(Math.round(dateObj.getMilliseconds() / 100)); + }, + SS: function(dateObj) { + return pad(Math.round(dateObj.getMilliseconds() / 10), 2); + }, + SSS: function(dateObj) { + return pad(dateObj.getMilliseconds(), 3); + }, + a: function(dateObj, i18n) { + return dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1]; + }, + A: function(dateObj, i18n) { + return dateObj.getHours() < 12 ? i18n.amPm[0].toUpperCase() : i18n.amPm[1].toUpperCase(); + }, + ZZ: function(dateObj) { + var offset2 = dateObj.getTimezoneOffset(); + return (offset2 > 0 ? "-" : "+") + pad(Math.floor(Math.abs(offset2) / 60) * 100 + Math.abs(offset2) % 60, 4); + }, + Z: function(dateObj) { + var offset2 = dateObj.getTimezoneOffset(); + return (offset2 > 0 ? "-" : "+") + pad(Math.floor(Math.abs(offset2) / 60), 2) + ":" + pad(Math.abs(offset2) % 60, 2); + } +}; +var globalMasks = { + default: "ddd MMM DD YYYY HH:mm:ss", + shortDate: "M/D/YY", + mediumDate: "MMM D, YYYY", + longDate: "MMMM D, YYYY", + fullDate: "dddd, MMMM D, YYYY", + isoDate: "YYYY-MM-DD", + isoDateTime: "YYYY-MM-DDTHH:mm:ssZ", + shortTime: "HH:mm", + mediumTime: "HH:mm:ss", + longTime: "HH:mm:ss.SSS" +}; +var format = function(dateObj, mask, i18n) { + if (mask === void 0) { + mask = globalMasks["default"]; + } + if (i18n === void 0) { + i18n = {}; + } + if (typeof dateObj === "number") { + dateObj = new Date(dateObj); + } + if (Object.prototype.toString.call(dateObj) !== "[object Date]" || isNaN(dateObj.getTime())) { + throw new Error("Invalid Date pass to format"); + } + mask = globalMasks[mask] || mask; + var literals = []; + mask = mask.replace(literal, function($0, $1) { + literals.push($1); + return "@@@"; + }); + var combinedI18nSettings = assign(assign({}, globalI18n), i18n); + mask = mask.replace(token, function($0) { + return formatFlags[$0](dateObj, combinedI18nSettings); + }); + return mask.replace(/@@@/g, function() { + return literals.shift(); + }); +}; +const _hoisted_1$3 = { class: "date" }; +const _hoisted_2$3 = { class: "title bold" }; +const _sfc_main$3 = { + __name: "NoteRow", + props: { note: Object }, + setup(__props) { + const { openNote } = useOpenNote(); + const formatDate = (date) => { + const d = new Date(date); + return format(d, "MM/DD/YYYY"); + }; + return (_ctx, _cache) => { + return openBlock(), createElementBlock("button", { + class: "note-row", + onClick: _cache[0] || (_cache[0] = ($event) => unref(openNote)(__props.note.id)) + }, [ + createBaseVNode("span", _hoisted_1$3, toDisplayString(formatDate(__props.note.createdAt)), 1), + createBaseVNode("span", _hoisted_2$3, toDisplayString(__props.note.title), 1) + ]); + }; + } +}; +const _hoisted_1$2 = { class: "directory layout-block" }; +const _hoisted_2$2 = { class: "notes" }; +const _sfc_main$2 = { + __name: "Directory", + setup(__props) { + const { categories: categories2, loadCategories, loadCategoryNotes } = useNotes(); + const notes = /* @__PURE__ */ ref(); + onMounted(async () => { + await loadCategories(); + notes.value = await loadCategoryNotes(); + }); + return (_ctx, _cache) => { + return openBlock(), createElementBlock("main", _hoisted_1$2, [ + (openBlock(true), createElementBlock(Fragment$1, null, renderList(unref(categories2), (category, i) => { + return openBlock(), createBlock(_sfc_main$4, { + index: i, + category, + key: category + }, null, 8, ["index", "category"]); + }), 128)), + _cache[0] || (_cache[0] = createBaseVNode("h2", { class: "label" }, "Summarium", -1)), + createBaseVNode("div", _hoisted_2$2, [ + (openBlock(true), createElementBlock(Fragment$1, null, renderList(notes.value, (note) => { + return openBlock(), createBlock(_sfc_main$3, { + note, + key: note.id + }, null, 8, ["note"]); + }), 128)) + ]) + ]); + }; + } +}; function OrderedMap(content) { this.content = content; } @@ -26176,8 +28206,8 @@ function createAtomBlockMarkdownSpec(options) { return filtered; }; return { - parseMarkdown: (token, h2) => { - const attrs = { ...defaultAttributes, ...token.attributes }; + parseMarkdown: (token2, h2) => { + const attrs = { ...defaultAttributes, ...token2.attributes }; return h2.createNode(nodeName, attrs, []); }, markdownTokenizer: { @@ -26241,17 +28271,17 @@ function createBlockMarkdownSpec(options) { return filtered; }; return { - parseMarkdown: (token, h2) => { + parseMarkdown: (token2, h2) => { let nodeContent; if (getContent) { - const contentResult = getContent(token); + const contentResult = getContent(token2); nodeContent = typeof contentResult === "string" ? [{ type: "text", text: contentResult }] : contentResult; } else if (content === "block") { - nodeContent = h2.parseChildren(token.tokens || []); + nodeContent = h2.parseChildren(token2.tokens || []); } else { - nodeContent = h2.parseInline(token.tokens || []); + nodeContent = h2.parseInline(token2.tokens || []); } - const attrs = { ...defaultAttributes, ...token.attributes }; + const attrs = { ...defaultAttributes, ...token2.attributes }; return h2.createNode(nodeName, attrs, nodeContent); }, markdownTokenizer: { @@ -26300,9 +28330,9 @@ function createBlockMarkdownSpec(options) { if (matchedContent) { if (content === "block") { contentTokens = lexer.blockTokens(rawContent); - contentTokens.forEach((token) => { - if (token.text && (!token.tokens || token.tokens.length === 0)) { - token.tokens = lexer.inlineTokens(token.text); + contentTokens.forEach((token2) => { + if (token2.text && (!token2.tokens || token2.tokens.length === 0)) { + token2.tokens = lexer.inlineTokens(token2.text); } }); while (contentTokens.length > 0) { @@ -26392,12 +28422,12 @@ function createInlineMarkdownSpec(options) { }; const escapedShortcode = shortcode.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); return { - parseMarkdown: (token, h2) => { - const attrs = { ...defaultAttributes, ...token.attributes }; + parseMarkdown: (token2, h2) => { + const attrs = { ...defaultAttributes, ...token2.attributes }; if (selfClosing) { return h2.createNode(nodeName, attrs); } - const content = getContent ? getContent(token) : token.content || ""; + const content = getContent ? getContent(token2) : token2.content || ""; if (content) { return h2.createNode(nodeName, attrs, [h2.createTextNode(content)]); } @@ -26523,8 +28553,8 @@ function parseIndentedBlocks(src, config, lexer) { } } } - const token = config.createToken(itemData, nestedTokens); - items.push(token); + const token2 = config.createToken(itemData, nestedTokens); + items.push(token2); } if (items.length === 0) { return void 0; @@ -28170,25 +30200,25 @@ var MarkdownManager = class { * Convert an array of marked tokens into Tiptap JSON nodes using registered extension handlers. */ parseTokens(tokens) { - return tokens.map((token) => this.parseToken(token)).filter((parsed) => parsed !== null).flatMap((parsed) => Array.isArray(parsed) ? parsed : [parsed]); + return tokens.map((token2) => this.parseToken(token2)).filter((parsed) => parsed !== null).flatMap((parsed) => Array.isArray(parsed) ? parsed : [parsed]); } /** * Parse a single token into Tiptap JSON using the appropriate registered handler. */ - parseToken(token) { - if (!token.type) { + parseToken(token2) { + if (!token2.type) { return null; } - if (token.type === "list") { - return this.parseListToken(token); + if (token2.type === "list") { + return this.parseListToken(token2); } - const handlers2 = this.getHandlersForToken(token.type); + const handlers2 = this.getHandlersForToken(token2.type); const helpers = this.createParseHelpers(); const result = handlers2.find((handler) => { if (!handler.parseMarkdown) { return false; } - const parseResult = handler.parseMarkdown(token, helpers); + const parseResult = handler.parseMarkdown(token2, helpers); const normalized = this.normalizeParseResult(parseResult); if (normalized && (!Array.isArray(normalized) || normalized.length > 0)) { this.lastParseResult = normalized; @@ -28201,7 +30231,7 @@ var MarkdownManager = class { this.lastParseResult = null; return toReturn; } - return this.parseFallbackToken(token); + return this.parseFallbackToken(token2); } /** * Parse a list token, handling mixed bullet and task list items by splitting them into separate lists. @@ -28210,20 +30240,20 @@ var MarkdownManager = class { * @param token The list token to parse * @returns Array of parsed list nodes, or null if parsing fails */ - parseListToken(token) { - if (!token.items || token.items.length === 0) { - return this.parseTokenWithHandlers(token); + parseListToken(token2) { + if (!token2.items || token2.items.length === 0) { + return this.parseTokenWithHandlers(token2); } - const hasTask = token.items.some((item) => isTaskItem(item).isTask); - const hasNonTask = token.items.some((item) => !isTaskItem(item).isTask); + const hasTask = token2.items.some((item) => isTaskItem(item).isTask); + const hasNonTask = token2.items.some((item) => !isTaskItem(item).isTask); if (!hasTask || !hasNonTask || this.getHandlersForToken("taskList").length === 0) { - return this.parseTokenWithHandlers(token); + return this.parseTokenWithHandlers(token2); } const groups = []; let currentGroup = []; let currentType = null; - for (let i = 0; i < token.items.length; i += 1) { - const item = token.items[i]; + for (let i = 0; i < token2.items.length; i += 1) { + const item = token2.items[i]; const { isTask, checked, indentLevel } = isTaskItem(item); let processedItem = item; if (isTask) { @@ -28281,7 +30311,7 @@ var MarkdownManager = class { const results = []; for (let i = 0; i < groups.length; i += 1) { const group = groups[i]; - const subToken = { ...token, type: group.type, items: group.items }; + const subToken = { ...token2, type: group.type, items: group.items }; const parsed = this.parseToken(subToken); if (parsed) { if (Array.isArray(parsed)) { @@ -28296,17 +30326,17 @@ var MarkdownManager = class { /** * Parse a token using registered handlers (extracted for reuse). */ - parseTokenWithHandlers(token) { - if (!token.type) { + parseTokenWithHandlers(token2) { + if (!token2.type) { return null; } - const handlers2 = this.getHandlersForToken(token.type); + const handlers2 = this.getHandlersForToken(token2.type); const helpers = this.createParseHelpers(); const result = handlers2.find((handler) => { if (!handler.parseMarkdown) { return false; } - const parseResult = handler.parseMarkdown(token, helpers); + const parseResult = handler.parseMarkdown(token2, helpers); const normalized = this.normalizeParseResult(parseResult); if (normalized && (!Array.isArray(normalized) || normalized.length > 0)) { this.lastParseResult = normalized; @@ -28319,7 +30349,7 @@ var MarkdownManager = class { this.lastParseResult = null; return toReturn; } - return this.parseFallbackToken(token); + return this.parseFallbackToken(token2); } /** * Creates helper functions for parsing markdown tokens. @@ -28369,14 +30399,14 @@ var MarkdownManager = class { var _a, _b, _c, _d; const result = []; for (let i = 0; i < tokens.length; i += 1) { - const token = tokens[i]; - if (token.type === "text") { + const token2 = tokens[i]; + if (token2.type === "text") { result.push({ type: "text", - text: token.text || "" + text: token2.text || "" }); - } else if (token.type === "html") { - const raw = ((_b = (_a = token.raw) != null ? _a : token.text) != null ? _b : "").toString(); + } else if (token2.type === "html") { + const raw = ((_b = (_a = token2.raw) != null ? _a : token2.text) != null ? _b : "").toString(); const isClosing = /^<\/[\s]*[\w-]+/i.test(raw); const openMatch = raw.match(/^<[\s]*([\w-]+)(\s|>|\/|$)/i); if (!isClosing && openMatch && !/\/>$/.test(raw)) { @@ -28415,7 +30445,7 @@ var MarkdownManager = class { continue; } } - const parsedSingle = this.parseHTMLToken(token); + const parsedSingle = this.parseHTMLToken(token2); if (parsedSingle) { const normalized = this.normalizeParseResult(parsedSingle); if (Array.isArray(normalized)) { @@ -28424,11 +30454,11 @@ var MarkdownManager = class { result.push(normalized); } } - } else if (token.type) { - const markHandler = this.getHandlerForToken(token.type); + } else if (token2.type) { + const markHandler = this.getHandlerForToken(token2.type); if (markHandler && markHandler.parseMarkdown) { const helpers = this.createParseHelpers(); - const parsed = markHandler.parseMarkdown(token, helpers); + const parsed = markHandler.parseMarkdown(token2, helpers); if (this.isMarkResult(parsed)) { const markedContent = this.applyMarkToContent(parsed.mark, parsed.content, parsed.attrs); result.push(...markedContent); @@ -28440,8 +30470,8 @@ var MarkdownManager = class { result.push(normalized); } } - } else if (token.tokens) { - result.push(...this.parseInlineTokens(token.tokens)); + } else if (token2.tokens) { + result.push(...this.parseInlineTokens(token2.tokens)); } } } @@ -28487,31 +30517,31 @@ var MarkdownManager = class { /** * Fallback parsing for common tokens when no specific handler is registered. */ - parseFallbackToken(token) { - switch (token.type) { + parseFallbackToken(token2) { + switch (token2.type) { case "paragraph": return { type: "paragraph", - content: token.tokens ? this.parseInlineTokens(token.tokens) : [] + content: token2.tokens ? this.parseInlineTokens(token2.tokens) : [] }; case "heading": return { type: "heading", - attrs: { level: token.depth || 1 }, - content: token.tokens ? this.parseInlineTokens(token.tokens) : [] + attrs: { level: token2.depth || 1 }, + content: token2.tokens ? this.parseInlineTokens(token2.tokens) : [] }; case "text": return { type: "text", - text: token.text || "" + text: token2.text || "" }; case "html": - return this.parseHTMLToken(token); + return this.parseHTMLToken(token2); case "space": return null; default: - if (token.tokens) { - return this.parseTokens(token.tokens); + if (token2.tokens) { + return this.parseTokens(token2.tokens); } return null; } @@ -28520,13 +30550,13 @@ var MarkdownManager = class { * Parse HTML tokens using extensions' parseHTML methods. * This allows HTML within markdown to be parsed according to extension rules. */ - parseHTMLToken(token) { - const html = token.text || token.raw || ""; + parseHTMLToken(token2) { + const html = token2.text || token2.raw || ""; if (!html.trim()) { return null; } if (typeof window === "undefined") { - if (token.block) { + if (token2.block) { return { type: "paragraph", content: [ @@ -28545,7 +30575,7 @@ var MarkdownManager = class { try { const parsed = generateJSON(html, this.baseExtensions); if (parsed.type === "doc" && parsed.content) { - if (token.block) { + if (token2.block) { return parsed.content; } if (parsed.content.length === 1 && parsed.content[0].type === "paragraph" && parsed.content[0].content) { @@ -28910,11 +30940,11 @@ var Image = Node3.create({ renderHTML({ HTMLAttributes }) { return ["img", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)]; }, - parseMarkdown: (token, helpers) => { + parseMarkdown: (token2, helpers) => { return helpers.createNode("image", { - src: token.href, - title: token.title, - alt: token.text + src: token2.href, + title: token2.title, + alt: token2.text }); }, renderMarkdown: (node) => { @@ -29850,7 +31880,7 @@ function mustPreserveItems(state) { } const historyKey = new PluginKey("history"); const closeHistoryKey = new PluginKey("closeHistory"); -function history(config = {}) { +function history$1(config = {}) { config = { depth: config.depth || 100, newGroupDelay: config.newGroupDelay || 500 @@ -30235,7 +32265,7 @@ var UndoRedo = Extension.create({ }; }, addProseMirrorPlugins() { - return [history(this.options)]; + return [history$1(this.options)]; }, addKeyboardShortcuts() { return { @@ -30278,8 +32308,8 @@ var Blockquote = Node3.create({ renderHTML({ HTMLAttributes }) { return /* @__PURE__ */ h("blockquote", { ...mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), children: /* @__PURE__ */ h("slot", {}) }); }, - parseMarkdown: (token, helpers) => { - return helpers.createNode("blockquote", void 0, helpers.parseChildren(token.tokens || [])); + parseMarkdown: (token2, helpers) => { + return helpers.createNode("blockquote", void 0, helpers.parseChildren(token2.tokens || [])); }, renderMarkdown: (node, h2) => { if (!node.content) { @@ -30363,8 +32393,8 @@ var Bold = Mark2.create({ return /* @__PURE__ */ h("strong", { ...mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), children: /* @__PURE__ */ h("slot", {}) }); }, markdownTokenName: "strong", - parseMarkdown: (token, helpers) => { - return helpers.applyMark("bold", helpers.parseInline(token.tokens || [])); + parseMarkdown: (token2, helpers) => { + return helpers.applyMark("bold", helpers.parseInline(token2.tokens || [])); }, renderMarkdown: (node, h2) => { return `**${h2.renderChildren(node)}**`; @@ -30432,8 +32462,8 @@ var Code = Mark2.create({ return ["code", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, markdownTokenName: "codespan", - parseMarkdown: (token, helpers) => { - return helpers.applyMark("code", [{ type: "text", text: token.text || "" }]); + parseMarkdown: (token2, helpers) => { + return helpers.applyMark("code", [{ type: "text", text: token2.text || "" }]); }, renderMarkdown: (node, h2) => { if (!node.content) { @@ -30541,15 +32571,15 @@ var CodeBlock = Node3.create({ ]; }, markdownTokenName: "code", - parseMarkdown: (token, helpers) => { + parseMarkdown: (token2, helpers) => { var _a; - if (((_a = token.raw) == null ? void 0 : _a.startsWith("```")) === false && token.codeBlockStyle !== "indented") { + if (((_a = token2.raw) == null ? void 0 : _a.startsWith("```")) === false && token2.codeBlockStyle !== "indented") { return []; } return helpers.createNode( "codeBlock", - { language: token.lang || null }, - token.text ? [helpers.createTextNode(token.text)] : [] + { language: token2.lang || null }, + token2.text ? [helpers.createTextNode(token2.text)] : [] ); }, renderMarkdown: (node, h2) => { @@ -30876,8 +32906,8 @@ var Heading = Node3.create({ const level = hasLevel ? node.attrs.level : this.options.levels[0]; return [`h${level}`, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, - parseMarkdown: (token, helpers) => { - return helpers.createNode("heading", { level: token.depth || 1 }, helpers.parseInline(token.tokens || [])); + parseMarkdown: (token2, helpers) => { + return helpers.createNode("heading", { level: token2.depth || 1 }, helpers.parseInline(token2.tokens || [])); }, renderMarkdown: (node, h2) => { var _a; @@ -30943,7 +32973,7 @@ var HorizontalRule = Node3.create({ return ["hr", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)]; }, markdownTokenName: "hr", - parseMarkdown: (token, helpers) => { + parseMarkdown: (token2, helpers) => { return helpers.createNode("horizontalRule"); }, renderMarkdown: () => { @@ -31047,8 +33077,8 @@ var Italic = Mark2.create({ }; }, markdownTokenName: "em", - parseMarkdown: (token, helpers) => { - return helpers.applyMark("italic", helpers.parseInline(token.tokens || [])); + parseMarkdown: (token2, helpers) => { + return helpers.applyMark("italic", helpers.parseInline(token2.tokens || [])); }, renderMarkdown: (node, h2) => { return `*${h2.renderChildren(node)}*`; @@ -31139,11 +33169,11 @@ function flagsForToken(t, groups) { } return result; } -function State(token = null) { +function State(token2 = null) { this.j = {}; this.jr = []; this.jd = null; - this.t = token; + this.t = token2; } State.groups = {}; State.prototype = { @@ -31738,8 +33768,8 @@ Options.prototype = { * @param {MultiToken} token * @returns {boolean} */ - check(token) { - return this.get("validate", token.toString(), token); + check(token2) { + return this.get("validate", token2.toString(), token2); }, // Private methods /** @@ -31753,19 +33783,19 @@ Options.prototype = { * @param {MultiToken} [token] The token from linkify.tokenize * @returns {Opts[K] | any} */ - get(key, operator, token) { + get(key, operator, token2) { const isCallable = operator != null; let option = this.o[key]; if (!option) { return option; } if (typeof option === "object") { - option = token.t in option ? option[token.t] : defaults[key]; + option = token2.t in option ? option[token2.t] : defaults[key]; if (typeof option === "function" && isCallable) { - option = option(operator, token); + option = option(operator, token2); } } else if (typeof option === "function" && isCallable) { - option = option(operator, token.t, token); + option = option(operator, token2.t, token2); } return option; }, @@ -31776,10 +33806,10 @@ Options.prototype = { * @param {MultiToken} [token] * @returns {Opts[L] | any} */ - getObj(key, operator, token) { + getObj(key, operator, token2) { let obj = this.o[key]; if (typeof obj === "function" && operator != null) { - obj = obj(operator, token.t, token); + obj = obj(operator, token2.t, token2); } return obj; }, @@ -31790,10 +33820,10 @@ Options.prototype = { * @returns {any} Render result; e.g., HTML string, DOM element, React * Component, etc. */ - render(token) { - const ir = token.render(this); - const renderFn = this.get("render", null, token) || this.defaultRender; - return renderFn(ir, token.t, token); + render(token2) { + const ir = token2.render(this); + const renderFn = this.get("render", null, token2) || this.defaultRender; + return renderFn(ir, token2.t, token2); } }; function noop(val) { @@ -31901,17 +33931,17 @@ MultiToken.prototype = { * @param {Options} options Formattinng options */ render(options) { - const token = this; + const token2 = this; const href = this.toHref(options.get("defaultProtocol")); const formattedHref = options.get("formatHref", href, this); - const tagName = options.get("tagName", href, token); + const tagName = options.get("tagName", href, token2); const content = this.toFormattedString(options); const attributes = {}; - const className = options.get("className", href, token); - const target = options.get("target", href, token); - const rel = options.get("rel", href, token); - const attrs = options.getObj("attributes", href, token); - const eventListeners = options.getObj("events", href, token); + const className = options.get("className", href, token2); + const target = options.get("target", href, token2); + const rel = options.get("rel", href, token2); + const attrs = options.getObj("attributes", href, token2); + const eventListeners = options.getObj("events", href, token2); attributes.href = formattedHref; if (className) { attributes.class = className; @@ -32223,9 +34253,9 @@ function find(str, type = null, opts = null) { const tokens = tokenize(str); const filtered = []; for (let i = 0; i < tokens.length; i++) { - const token = tokens[i]; - if (token.isLink && (!type || token.t === type) && options.check(token)) { - filtered.push(token.toFormattedObject(options)); + const token2 = tokens[i]; + if (token2.isLink && (!type || token2.t === type) && options.check(token2)) { + filtered.push(token2.toFormattedObject(options)); } } return filtered; @@ -32522,10 +34552,10 @@ var Link2 = Mark2.create({ return ["a", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, markdownTokenName: "link", - parseMarkdown: (token, helpers) => { - return helpers.applyMark("link", helpers.parseInline(token.tokens || []), { - href: token.href, - title: token.title || null + parseMarkdown: (token2, helpers) => { + return helpers.applyMark("link", helpers.parseInline(token2.tokens || []), { + href: token2.href, + title: token2.title || null }); }, renderMarkdown: (node, h2) => { @@ -32672,13 +34702,13 @@ var BulletList = Node3.create({ return ["ul", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, markdownTokenName: "list", - parseMarkdown: (token, helpers) => { - if (token.type !== "list" || token.ordered) { + parseMarkdown: (token2, helpers) => { + if (token2.type !== "list" || token2.ordered) { return []; } return { type: "bulletList", - content: token.items ? helpers.parseChildren(token.items) : [] + content: token2.items ? helpers.parseChildren(token2.items) : [] }; }, renderMarkdown: (node, h2) => { @@ -32747,17 +34777,17 @@ var ListItem = Node3.create({ return ["li", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, markdownTokenName: "list_item", - parseMarkdown: (token, helpers) => { - if (token.type !== "list_item") { + parseMarkdown: (token2, helpers) => { + if (token2.type !== "list_item") { return []; } let content = []; - if (token.tokens && token.tokens.length > 0) { - const hasParagraphTokens = token.tokens.some((t) => t.type === "paragraph"); + if (token2.tokens && token2.tokens.length > 0) { + const hasParagraphTokens = token2.tokens.some((t) => t.type === "paragraph"); if (hasParagraphTokens) { - content = helpers.parseChildren(token.tokens); + content = helpers.parseChildren(token2.tokens); } else { - const firstToken = token.tokens[0]; + const firstToken = token2.tokens[0]; if (firstToken && firstToken.type === "text" && firstToken.tokens && firstToken.tokens.length > 0) { const inlineContent = helpers.parseInline(firstToken.tokens); content = [ @@ -32766,13 +34796,13 @@ var ListItem = Node3.create({ content: inlineContent } ]; - if (token.tokens.length > 1) { - const remainingTokens = token.tokens.slice(1); + if (token2.tokens.length > 1) { + const remainingTokens = token2.tokens.slice(1); const additionalContent = helpers.parseChildren(remainingTokens); content.push(...additionalContent); } } else { - content = helpers.parseChildren(token.tokens); + content = helpers.parseChildren(token2.tokens); } } } @@ -33226,12 +35256,12 @@ var OrderedList = Node3.create({ return start === 1 ? ["ol", mergeAttributes(this.options.HTMLAttributes, attributesWithoutStart), 0] : ["ol", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, markdownTokenName: "list", - parseMarkdown: (token, helpers) => { - if (token.type !== "list" || !token.ordered) { + parseMarkdown: (token2, helpers) => { + if (token2.type !== "list" || !token2.ordered) { return []; } - const startValue = token.start || 1; - const content = token.items ? parseListItems(token.items, helpers) : []; + const startValue = token2.start || 1; + const content = token2.items ? parseListItems(token2.items, helpers) : []; if (startValue !== 1) { return { type: "orderedList", @@ -33376,20 +35406,20 @@ var TaskItem = Node3.create({ ["div", 0] ]; }, - parseMarkdown: (token, h2) => { + parseMarkdown: (token2, h2) => { const content = []; - if (token.tokens && token.tokens.length > 0) { - content.push(h2.createNode("paragraph", {}, h2.parseInline(token.tokens))); - } else if (token.text) { - content.push(h2.createNode("paragraph", {}, [h2.createNode("text", { text: token.text })])); + if (token2.tokens && token2.tokens.length > 0) { + content.push(h2.createNode("paragraph", {}, h2.parseInline(token2.tokens))); + } else if (token2.text) { + content.push(h2.createNode("paragraph", {}, [h2.createNode("text", { text: token2.text })])); } else { content.push(h2.createNode("paragraph", {}, [])); } - if (token.nestedTokens && token.nestedTokens.length > 0) { - const nestedContent = h2.parseChildren(token.nestedTokens); + if (token2.nestedTokens && token2.nestedTokens.length > 0) { + const nestedContent = h2.parseChildren(token2.nestedTokens); content.push(...nestedContent); } - return h2.createNode("taskItem", { checked: token.checked || false }, content); + return h2.createNode("taskItem", { checked: token2.checked || false }, content); }, renderMarkdown: (node, h2) => { var _a; @@ -33537,8 +35567,8 @@ var TaskList = Node3.create({ renderHTML({ HTMLAttributes }) { return ["ul", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { "data-type": this.name }), 0]; }, - parseMarkdown: (token, h2) => { - return h2.createNode("taskList", {}, h2.parseChildren(token.items || [])); + parseMarkdown: (token2, h2) => { + return h2.createNode("taskList", {}, h2.parseChildren(token2.items || [])); }, renderMarkdown: (node, h2) => { if (!node.content) { @@ -33684,8 +35714,8 @@ var Paragraph = Node3.create({ renderHTML({ HTMLAttributes }) { return ["p", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, - parseMarkdown: (token, helpers) => { - const tokens = token.tokens || []; + parseMarkdown: (token2, helpers) => { + const tokens = token2.tokens || []; if (tokens.length === 1 && tokens[0].type === "image") { return helpers.parseChildren([tokens[0]]); } @@ -33749,8 +35779,8 @@ var Strike = Mark2.create({ return ["s", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, markdownTokenName: "del", - parseMarkdown: (token, helpers) => { - return helpers.applyMark("strike", helpers.parseInline(token.tokens || [])); + parseMarkdown: (token2, helpers) => { + return helpers.applyMark("strike", helpers.parseInline(token2.tokens || [])); }, renderMarkdown: (node, h2) => { return `~~${h2.renderChildren(node)}~~`; @@ -33793,10 +35823,10 @@ var Strike = Mark2.create({ var Text = Node3.create({ name: "text", group: "inline", - parseMarkdown: (token) => { + parseMarkdown: (token2) => { return { type: "text", - text: token.text || "" + text: token2.text || "" }; }, renderMarkdown: (node) => node.text || "" @@ -33823,8 +35853,8 @@ var Underline = Mark2.create({ renderHTML({ HTMLAttributes }) { return ["u", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; }, - parseMarkdown(token, helpers) { - return helpers.applyMark(this.name || "underline", helpers.parseInline(token.tokens || [])); + parseMarkdown(token2, helpers) { + return helpers.applyMark(this.name || "underline", helpers.parseInline(token2.tokens || [])); }, renderMarkdown(node, helpers) { return `++${helpers.renderChildren(node)}++`; @@ -36635,496 +38665,334 @@ var BubbleMenu = /* @__PURE__ */ defineComponent({ }; } }); -var FloatingMenuView = class { - constructor({ - editor, - element, - view, - updateDelay = 250, - resizeDelay = 60, - options, - appendTo, - shouldShow - }) { - this.preventHide = false; - this.isVisible = false; - this.scrollTarget = window; - this.shouldShow = ({ view: view2, state }) => { - const { selection } = state; - const { $anchor, empty: empty2 } = selection; - const isRootDepth = $anchor.depth === 1; - const isEmptyTextBlock = $anchor.parent.isTextblock && !$anchor.parent.type.spec.code && !$anchor.parent.textContent && $anchor.parent.childCount === 0 && !this.getTextContent($anchor.parent); - if (!view2.hasFocus() || !empty2 || !isRootDepth || !isEmptyTextBlock || !this.editor.isEditable) { - return false; - } - return true; - }; - this.floatingUIOptions = { - strategy: "absolute", - placement: "right", - offset: 8, - flip: {}, - shift: {}, - arrow: false, - size: false, - autoPlacement: false, - hide: false, - inline: false - }; - this.updateHandler = (view2, selectionChanged, docChanged, oldState) => { - const { composing } = view2; - const isSame = !selectionChanged && !docChanged; - if (composing || isSame) { - return; - } - const shouldShow2 = this.getShouldShow(oldState); - if (!shouldShow2) { - this.hide(); - return; - } - this.updatePosition(); - this.show(); - }; - this.mousedownHandler = () => { - this.preventHide = true; - }; - this.focusHandler = () => { - setTimeout(() => this.update(this.editor.view)); - }; - this.blurHandler = ({ event }) => { - var _a2; - if (this.preventHide) { - this.preventHide = false; - return; - } - if ((event == null ? void 0 : event.relatedTarget) && ((_a2 = this.element.parentNode) == null ? void 0 : _a2.contains(event.relatedTarget))) { - return; - } - if ((event == null ? void 0 : event.relatedTarget) === this.editor.view.dom) { - return; - } - this.hide(); - }; - this.transactionHandler = ({ transaction: tr2 }) => { - const meta = tr2.getMeta("floatingMenu"); - if (meta === "updatePosition") { - this.updatePosition(); - } else if (meta && typeof meta === "object" && meta.type === "updateOptions") { - this.updateOptions(meta.options); - } - }; - this.resizeHandler = () => { - if (this.resizeDebounceTimer) { - clearTimeout(this.resizeDebounceTimer); - } - this.resizeDebounceTimer = window.setTimeout(() => { - this.updatePosition(); - }, this.resizeDelay); - }; - var _a; - this.editor = editor; - this.element = element; - this.view = view; - this.updateDelay = updateDelay; - this.resizeDelay = resizeDelay; - this.appendTo = appendTo; - this.scrollTarget = (_a = options == null ? void 0 : options.scrollTarget) != null ? _a : window; - this.floatingUIOptions = { - ...this.floatingUIOptions, - ...options - }; - this.element.tabIndex = 0; - if (shouldShow) { - this.shouldShow = shouldShow; - } - this.element.addEventListener("mousedown", this.mousedownHandler, { capture: true }); - this.editor.on("focus", this.focusHandler); - this.editor.on("blur", this.blurHandler); - this.editor.on("transaction", this.transactionHandler); - window.addEventListener("resize", this.resizeHandler); - this.scrollTarget.addEventListener("scroll", this.resizeHandler); - this.update(view, view.state); - if (this.getShouldShow()) { - this.show(); - this.updatePosition(); +var now_1; +var hasRequiredNow; +function requireNow() { + if (hasRequiredNow) return now_1; + hasRequiredNow = 1; + var root = require_root(); + var now = function() { + return root.Date.now(); + }; + now_1 = now; + return now_1; +} +var _trimmedEndIndex; +var hasRequired_trimmedEndIndex; +function require_trimmedEndIndex() { + if (hasRequired_trimmedEndIndex) return _trimmedEndIndex; + hasRequired_trimmedEndIndex = 1; + var reWhitespace = /\s/; + function trimmedEndIndex(string) { + var index2 = string.length; + while (index2-- && reWhitespace.test(string.charAt(index2))) { } + return index2; } - getTextContent(node) { - return getText(node, { textSerializers: getTextSerializersFromSchema(this.editor.schema) }); + _trimmedEndIndex = trimmedEndIndex; + return _trimmedEndIndex; +} +var _baseTrim; +var hasRequired_baseTrim; +function require_baseTrim() { + if (hasRequired_baseTrim) return _baseTrim; + hasRequired_baseTrim = 1; + var trimmedEndIndex = require_trimmedEndIndex(); + var reTrimStart = /^\s+/; + function baseTrim(string) { + return string ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, "") : string; } - get middlewares() { - const middlewares = []; - if (this.floatingUIOptions.flip) { - middlewares.push(flip(typeof this.floatingUIOptions.flip !== "boolean" ? this.floatingUIOptions.flip : void 0)); - } - if (this.floatingUIOptions.shift) { - middlewares.push( - shift(typeof this.floatingUIOptions.shift !== "boolean" ? this.floatingUIOptions.shift : void 0) - ); - } - if (this.floatingUIOptions.offset) { - middlewares.push( - offset(typeof this.floatingUIOptions.offset !== "boolean" ? this.floatingUIOptions.offset : void 0) - ); - } - if (this.floatingUIOptions.arrow) { - middlewares.push(arrow$1(this.floatingUIOptions.arrow)); - } - if (this.floatingUIOptions.size) { - middlewares.push(size(typeof this.floatingUIOptions.size !== "boolean" ? this.floatingUIOptions.size : void 0)); - } - if (this.floatingUIOptions.autoPlacement) { - middlewares.push( - autoPlacement( - typeof this.floatingUIOptions.autoPlacement !== "boolean" ? this.floatingUIOptions.autoPlacement : void 0 - ) - ); - } - if (this.floatingUIOptions.hide) { - middlewares.push(hide(typeof this.floatingUIOptions.hide !== "boolean" ? this.floatingUIOptions.hide : void 0)); - } - if (this.floatingUIOptions.inline) { - middlewares.push( - inline(typeof this.floatingUIOptions.inline !== "boolean" ? this.floatingUIOptions.inline : void 0) - ); - } - return middlewares; + _baseTrim = baseTrim; + return _baseTrim; +} +var isObjectLike_1; +var hasRequiredIsObjectLike; +function requireIsObjectLike() { + if (hasRequiredIsObjectLike) return isObjectLike_1; + hasRequiredIsObjectLike = 1; + function isObjectLike(value) { + return value != null && typeof value == "object"; } - getShouldShow(oldState) { - var _a; - const { state } = this.view; - const { selection } = state; - const { ranges } = selection; - const from2 = Math.min(...ranges.map((range) => range.$from.pos)); - const to = Math.max(...ranges.map((range) => range.$to.pos)); - const shouldShow = (_a = this.shouldShow) == null ? void 0 : _a.call(this, { - editor: this.editor, - view: this.view, - state, - oldState, - from: from2, - to - }); - return shouldShow; + isObjectLike_1 = isObjectLike; + return isObjectLike_1; +} +var isSymbol_1; +var hasRequiredIsSymbol; +function requireIsSymbol() { + if (hasRequiredIsSymbol) return isSymbol_1; + hasRequiredIsSymbol = 1; + var baseGetTag = require_baseGetTag(), isObjectLike = requireIsObjectLike(); + var symbolTag = "[object Symbol]"; + function isSymbol2(value) { + return typeof value == "symbol" || isObjectLike(value) && baseGetTag(value) == symbolTag; } - updateOptions(newProps) { - var _a; - if (newProps.updateDelay !== void 0) { - this.updateDelay = newProps.updateDelay; + isSymbol_1 = isSymbol2; + return isSymbol_1; +} +var toNumber_1; +var hasRequiredToNumber; +function requireToNumber() { + if (hasRequiredToNumber) return toNumber_1; + hasRequiredToNumber = 1; + var baseTrim = require_baseTrim(), isObject2 = requireIsObject(), isSymbol2 = requireIsSymbol(); + var NAN = 0 / 0; + var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + var reIsBinary = /^0b[01]+$/i; + var reIsOctal = /^0o[0-7]+$/i; + var freeParseInt = parseInt; + function toNumber(value) { + if (typeof value == "number") { + return value; } - if (newProps.resizeDelay !== void 0) { - this.resizeDelay = newProps.resizeDelay; + if (isSymbol2(value)) { + return NAN; } - if (newProps.appendTo !== void 0) { - this.appendTo = newProps.appendTo; + if (isObject2(value)) { + var other = typeof value.valueOf == "function" ? value.valueOf() : value; + value = isObject2(other) ? other + "" : other; } - if (newProps.shouldShow !== void 0) { - if (newProps.shouldShow) { - this.shouldShow = newProps.shouldShow; + if (typeof value != "string") { + return value === 0 ? value : +value; + } + value = baseTrim(value); + var isBinary = reIsBinary.test(value); + return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value; + } + toNumber_1 = toNumber; + return toNumber_1; +} +var debounce_1; +var hasRequiredDebounce; +function requireDebounce() { + if (hasRequiredDebounce) return debounce_1; + hasRequiredDebounce = 1; + var isObject2 = requireIsObject(), now = requireNow(), toNumber = requireToNumber(); + var FUNC_ERROR_TEXT = "Expected a function"; + var nativeMax = Math.max, nativeMin = Math.min; + function debounce2(func, wait, options) { + var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true; + if (typeof func != "function") { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = toNumber(wait) || 0; + if (isObject2(options)) { + leading = !!options.leading; + maxing = "maxWait" in options; + maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; + trailing = "trailing" in options ? !!options.trailing : trailing; + } + function invokeFunc(time) { + var args = lastArgs, thisArg = lastThis; + lastArgs = lastThis = void 0; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; + } + function leadingEdge(time) { + lastInvokeTime = time; + timerId = setTimeout(timerExpired, wait); + return leading ? invokeFunc(time) : result; + } + function remainingWait(time) { + var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, timeWaiting = wait - timeSinceLastCall; + return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting; + } + function shouldInvoke(time) { + var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime; + return lastCallTime === void 0 || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait; + } + function timerExpired() { + var time = now(); + if (shouldInvoke(time)) { + return trailingEdge(time); } + timerId = setTimeout(timerExpired, remainingWait(time)); } - if (newProps.options !== void 0) { - const newScrollTarget = (_a = newProps.options.scrollTarget) != null ? _a : window; - if (newScrollTarget !== this.scrollTarget) { - this.scrollTarget.removeEventListener("scroll", this.resizeHandler); - this.scrollTarget = newScrollTarget; - this.scrollTarget.addEventListener("scroll", this.resizeHandler); + function trailingEdge(time) { + timerId = void 0; + if (trailing && lastArgs) { + return invokeFunc(time); } - this.floatingUIOptions = { - ...this.floatingUIOptions, - ...newProps.options - }; + lastArgs = lastThis = void 0; + return result; } - } - updatePosition() { - const { selection } = this.editor.state; - const domRect = posToDOMRect(this.view, selection.from, selection.to); - const virtualElement = { - getBoundingClientRect: () => domRect, - getClientRects: () => [domRect] - }; - computePosition(virtualElement, this.element, { - placement: this.floatingUIOptions.placement, - strategy: this.floatingUIOptions.strategy, - middleware: this.middlewares - }).then(({ x: x2, y: y2, strategy, middlewareData }) => { - var _a, _b; - if (((_a = middlewareData.hide) == null ? void 0 : _a.referenceHidden) || ((_b = middlewareData.hide) == null ? void 0 : _b.escaped)) { - this.element.style.visibility = "hidden"; - return; + function cancel() { + if (timerId !== void 0) { + clearTimeout(timerId); } - this.element.style.visibility = "visible"; - this.element.style.width = "max-content"; - this.element.style.position = strategy; - this.element.style.left = `${x2}px`; - this.element.style.top = `${y2}px`; - if (this.isVisible && this.floatingUIOptions.onUpdate) { - this.floatingUIOptions.onUpdate(); + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = void 0; + } + function flush() { + return timerId === void 0 ? result : trailingEdge(now()); + } + function debounced() { + var time = now(), isInvoking = shouldInvoke(time); + lastArgs = arguments; + lastThis = this; + lastCallTime = time; + if (isInvoking) { + if (timerId === void 0) { + return leadingEdge(lastCallTime); + } + if (maxing) { + clearTimeout(timerId); + timerId = setTimeout(timerExpired, wait); + return invokeFunc(lastCallTime); + } } - }); - } - update(view, oldState) { - const selectionChanged = !(oldState == null ? void 0 : oldState.selection.eq(view.state.selection)); - const docChanged = !(oldState == null ? void 0 : oldState.doc.eq(view.state.doc)); - this.updateHandler(view, selectionChanged, docChanged, oldState); - } - show() { - var _a; - if (this.isVisible) { - return; - } - this.element.style.visibility = "visible"; - this.element.style.opacity = "1"; - const appendToElement = typeof this.appendTo === "function" ? this.appendTo() : this.appendTo; - (_a = appendToElement != null ? appendToElement : this.view.dom.parentElement) == null ? void 0 : _a.appendChild(this.element); - if (this.floatingUIOptions.onShow) { - this.floatingUIOptions.onShow(); - } - this.isVisible = true; - } - hide() { - if (!this.isVisible) { - return; - } - this.element.style.visibility = "hidden"; - this.element.style.opacity = "0"; - this.element.remove(); - if (this.floatingUIOptions.onHide) { - this.floatingUIOptions.onHide(); - } - this.isVisible = false; - } - destroy() { - this.hide(); - this.element.removeEventListener("mousedown", this.mousedownHandler, { capture: true }); - window.removeEventListener("resize", this.resizeHandler); - this.scrollTarget.removeEventListener("scroll", this.resizeHandler); - this.editor.off("focus", this.focusHandler); - this.editor.off("blur", this.blurHandler); - this.editor.off("transaction", this.transactionHandler); - if (this.floatingUIOptions.onDestroy) { - this.floatingUIOptions.onDestroy(); - } - } -}; -var FloatingMenuPlugin = (options) => { - return new Plugin({ - key: typeof options.pluginKey === "string" ? new PluginKey(options.pluginKey) : options.pluginKey, - view: (view) => new FloatingMenuView({ view, ...options }) - }); -}; -var FloatingMenu = /* @__PURE__ */ defineComponent({ - name: "FloatingMenu", - inheritAttrs: false, - props: { - pluginKey: { - // TODO: TypeScript breaks :( - // type: [String, Object as PropType>], - type: null, - default: "floatingMenu" - }, - editor: { - type: Object, - required: true - }, - updateDelay: { - type: Number, - default: void 0 - }, - resizeDelay: { - type: Number, - default: void 0 - }, - options: { - type: Object, - default: () => ({}) - }, - appendTo: { - type: [Object, Function], - default: void 0 - }, - shouldShow: { - type: Function, - default: null - } - }, - setup(props, { slots, attrs }) { - const root = /* @__PURE__ */ ref(null); - onMounted(() => { - const { pluginKey, editor, updateDelay, resizeDelay, options, appendTo, shouldShow } = props; - const el = root.value; - if (!el) { - return; + if (timerId === void 0) { + timerId = setTimeout(timerExpired, wait); } - el.style.visibility = "hidden"; - el.style.position = "absolute"; - el.remove(); - editor.registerPlugin( - FloatingMenuPlugin({ - pluginKey, - editor, - element: el, - updateDelay, - resizeDelay, - options, - appendTo, - shouldShow - }) - ); - }); - onBeforeUnmount(() => { - const { pluginKey, editor } = props; - editor.unregisterPlugin(pluginKey); - }); - return () => { - var _a; - return h$1("div", { ref: root, ...attrs }, (_a = slots.default) == null ? void 0 : _a.call(slots)); - }; + return result; + } + debounced.cancel = cancel; + debounced.flush = flush; + return debounced; } -}); -const _hoisted_1 = { + debounce_1 = debounce2; + return debounce_1; +} +var debounceExports = requireDebounce(); +const _debounce = /* @__PURE__ */ getDefaultExportFromCjs(debounceExports); +const _hoisted_1$1 = { key: 0, class: "editor layout-block" }; -const _hoisted_2 = { class: "bubble-menu" }; -const _hoisted_3 = { class: "floating-menu" }; -const initialMarkdown = `# My Document - -This is a paragraph. - -# Section - -- Item one -- Item two - ---- -# Header Three - -[Link](https://google.com) -`; +const _hoisted_2$1 = { class: "bubble-menu" }; const _sfc_main$1 = { - __name: "Index", + __name: "Editor", setup(__props) { + const route = useRoute(); + const id = route.params.id; + const { loadNote, updateNoteContent, updateNoteMetadata } = useNotes(); const CustomDocument = index_default$1.extend({ content: "heading block*" }); - const editor = new Editor2({ - extensions: [ - CustomDocument, - index_default.configure({ - document: false, - heading: { levels: [1] }, - trailingNode: { - node: "paragraph" - } - }), - Placeholder.configure({ - placeholder: ({ node }) => { - if (node.type.name === "heading") { - return "Title"; + const editor = /* @__PURE__ */ shallowRef(); + const updateNote = _debounce(async ({ editor: editor2 }) => { + const markdown = editor2.getMarkdown(); + await updateNoteContent(id, markdown); + updateTitle(editor2); + }, 300); + let lastTitle; + const updateTitle = _debounce(async (editor2) => { + const doc2 = editor2.state.doc; + const firstNode = doc2.firstChild; + if (!firstNode || firstNode.type.name !== "heading") return; + const newTitle = firstNode.textContent.trim() || "Untitled"; + if (newTitle === lastTitle) return; + lastTitle = newTitle; + await updateNoteMetadata(id, { title: newTitle }); + }, 300); + onMounted(async () => { + const note = await loadNote(id); + lastTitle = note.title; + editor.value = new Editor2({ + extensions: [ + CustomDocument, + index_default.configure({ + document: false, + heading: { levels: [1] }, + trailingNode: { + node: "paragraph" } - } - }), - Markdown, - index_default$2 - ], - content: initialMarkdown, - contentType: "markdown" + }), + Placeholder.configure({ + placeholder: ({ node }) => { + if (node.type.name === "heading") { + return "Title"; + } + } + }), + Markdown, + index_default$2 + ], + content: note.content, + contentType: "markdown", + onUpdate: updateNote + }); }); onBeforeUnmount(() => { - editor.destroy(); + editor.value?.destroy?.(); }); return (_ctx, _cache) => { - return unref(editor) ? (openBlock(), createElementBlock("div", _hoisted_1, [ - createVNode(unref(BubbleMenu), { editor: unref(editor) }, { + return editor.value ? (openBlock(), createElementBlock("div", _hoisted_1$1, [ + createVNode(unref(BubbleMenu), { editor: editor.value }, { default: withCtx(() => [ - createBaseVNode("div", _hoisted_2, [ + createBaseVNode("div", _hoisted_2$1, [ createBaseVNode("button", { - onClick: _cache[0] || (_cache[0] = ($event) => unref(editor).chain().focus().toggleBold().run()), - class: normalizeClass({ active: unref(editor).isActive("bold") }) + onClick: _cache[0] || (_cache[0] = ($event) => editor.value.chain().focus().toggleBold().run()), + class: normalizeClass({ active: editor.value.isActive("bold") }) }, " Bold ", 2), createBaseVNode("button", { - onClick: _cache[1] || (_cache[1] = ($event) => unref(editor).chain().focus().toggleItalic().run()), - class: normalizeClass({ active: unref(editor).isActive("italic") }) + onClick: _cache[1] || (_cache[1] = ($event) => editor.value.chain().focus().toggleItalic().run()), + class: normalizeClass({ active: editor.value.isActive("italic") }) }, " Italic ", 2) ]) ]), _: 1 }, 8, ["editor"]), - createVNode(unref(FloatingMenu), { editor: unref(editor) }, { - default: withCtx(() => [ - createBaseVNode("div", _hoisted_3, [ - createBaseVNode("button", { - onClick: _cache[2] || (_cache[2] = ($event) => unref(editor).chain().focus().toggleHeading({ level: 1 }).run()), - class: normalizeClass({ - active: unref(editor).isActive("heading", { level: 1 }) - }) - }, " H1 ", 2), - createBaseVNode("button", { - onClick: _cache[3] || (_cache[3] = ($event) => unref(editor).chain().focus().toggleBulletList().run()), - class: normalizeClass({ active: unref(editor).isActive("bulletList") }) - }, " Bullet List ", 2), - createBaseVNode("button", { - onClick: _cache[4] || (_cache[4] = ($event) => unref(editor).chain().focus().toggleOrderedList().run()), - class: normalizeClass({ active: unref(editor).isActive("orderedlist") }) - }, " Number List ", 2) - ]) - ]), - _: 1 - }, 8, ["editor"]), createVNode(unref(EditorContent), { - editor: unref(editor), + editor: editor.value, class: "editor-wrap" }, null, 8, ["editor"]) ])) : createCommentVNode("", true); }; } }; +const _hoisted_1 = { class: "category layout-block" }; +const _hoisted_2 = { class: "notes" }; const _sfc_main = { - __name: "App", + __name: "Category", setup(__props) { - const { height } = /* @__PURE__ */ useWindowSize(); - const classes = computed(() => [ - "container", - { "fonts-ready": !fontsLoading.value }, - "theme-dark" - ]); - const fontsLoading = /* @__PURE__ */ ref(true); + const route = useRoute(); + const id = route.params.id; + const { categories: categories2, loadCategoryNotes } = useNotes(); + const notes = /* @__PURE__ */ ref(); onMounted(async () => { - loadFonts([ - { - name: "Leibniz Fraktur", - weights: [400] - }, - { - name: "Geist Mono", - weights: [400, 700] - } - ]).then(() => { - fontsLoading.value = false; - }).catch(() => { - fontsLoading.value = false; - }); + notes.value = await loadCategoryNotes(id); + }); + const categoryIndex = computed(() => { + return categories2.value?.findIndex((category) => category === id) || 0; }); - const styles = computed(() => ({ - "--vh": height.value ? height.value / 100 + "px" : "100vh" - })); return (_ctx, _cache) => { - return openBlock(), createBlock(_sfc_main$2, { - root: "", - options: { duration: 1 } - }, { - default: withCtx(() => [ - createBaseVNode("div", { - class: normalizeClass(classes.value), - style: normalizeStyle(styles.value) - }, [ - createVNode(_sfc_main$1) - ], 6) - ]), - _: 1 - }); + const _component_router_link = resolveComponent("router-link"); + return openBlock(), createElementBlock("main", _hoisted_1, [ + createVNode(_component_router_link, { + class: "back", + to: "/" + }, { + default: withCtx(() => [..._cache[0] || (_cache[0] = [ + createTextVNode("<- Go Back", -1) + ])]), + _: 1 + }), + createVNode(_sfc_main$4, { + index: categoryIndex.value, + category: unref(id) + }, null, 8, ["index", "category"]), + createBaseVNode("div", _hoisted_2, [ + (openBlock(true), createElementBlock(Fragment$1, null, renderList(notes.value, (note) => { + return openBlock(), createBlock(_sfc_main$3, { + note, + key: note.id + }, null, 8, ["note"]); + }), 128)) + ]) + ]); }; } }; -createApp(_sfc_main).mount("#app"); +const routes = [ + { path: "/", name: "directory", component: _sfc_main$2 }, + { path: "/note/:id", name: "note", component: _sfc_main$1 }, + { path: "/category/:id", name: "category", component: _sfc_main } +]; +const router = createRouter({ + history: createWebHistory(), + routes +}); +const app = createApp(_sfc_main$5); +app.use(router); +app.mount("#app"); diff --git a/out/renderer/index.html b/out/renderer/index.html index 92f623c..9180e4d 100644 --- a/out/renderer/index.html +++ b/out/renderer/index.html @@ -8,8 +8,8 @@ http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:" /> - - + + diff --git a/package-lock.json b/package-lock.json index 170dcbf..6597b72 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,12 +22,12 @@ "electron-updater": "^6.3.9", "fecha": "^4.2.3", "flexsearch": "^0.8.212", - "gray-matter": "^4.0.3", "gsap": "^3.14.2", "lenis": "^1.3.17", "lodash": "^4.17.23", "sass": "^1.97.3", "sass-embedded": "^1.97.3", + "takerofnotes-plugin-filesystem": "^1.6.0", "tempus": "^1.0.0-dev.17", "uuid": "^13.0.0", "vue-router": "^5.0.3" @@ -8314,6 +8314,25 @@ "node": ">=16.0.0" } }, + "node_modules/takerofnotes-plugin-filesystem": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/takerofnotes-plugin-filesystem/-/takerofnotes-plugin-filesystem-1.6.0.tgz", + "integrity": "sha512-wUcH8lV6ges9zkEU7b7h1SkDcvgoJ+TLfogqRirLg38fdJ/LGat6BBfItO3QlalkYobsb4wglEfd7wg4f4erJA==", + "license": "MIT", + "dependencies": { + "gray-matter": "^4.0.3", + "takerofnotes-plugin-sdk": "^0.4.0" + } + }, + "node_modules/takerofnotes-plugin-sdk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/takerofnotes-plugin-sdk/-/takerofnotes-plugin-sdk-0.4.0.tgz", + "integrity": "sha512-C1bXun19Zh603Aq/7sEI4c3dZ8QEUiz51ikDPJm5g+JWoQkH77OH6AY19SN+eOKnqEmY1yw3JYEVd//mJ06UAA==", + "license": "MIT", + "dependencies": { + "zod": "^4.3.6" + } + }, "node_modules/tar": { "version": "7.5.9", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.9.tgz", @@ -9535,6 +9554,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index 800bdb7..bf7fccf 100644 --- a/package.json +++ b/package.json @@ -37,12 +37,12 @@ "electron-updater": "^6.3.9", "fecha": "^4.2.3", "flexsearch": "^0.8.212", - "gray-matter": "^4.0.3", "gsap": "^3.14.2", "lenis": "^1.3.17", "lodash": "^4.17.23", "sass": "^1.97.3", "sass-embedded": "^1.97.3", + "takerofnotes-plugin-filesystem": "^1.6.0", "tempus": "^1.0.0-dev.17", "uuid": "^13.0.0", "vue-router": "^5.0.3" diff --git a/src/main/core/BaseNotesAdapter.js b/src/main/core/BaseNotesAdapter.js deleted file mode 100644 index be74ed8..0000000 --- a/src/main/core/BaseNotesAdapter.js +++ /dev/null @@ -1,25 +0,0 @@ -export default class BaseNotesAdapter { - constructor(config = {}) { - this.config = config - } - - async init() { - throw new Error('init() not implemented') - } - - async getAll() { - throw new Error('getAll() not implemented') - } - - async create(note) { - throw new Error('create() not implemented') - } - - async update(note) { - throw new Error('update() not implemented') - } - - async delete(id) { - throw new Error('delete() not implemented') - } -} diff --git a/src/main/core/PluginConfig.js b/src/main/core/PluginConfig.js index 7b804cf..810dfc4 100644 --- a/src/main/core/PluginConfig.js +++ b/src/main/core/PluginConfig.js @@ -2,13 +2,34 @@ import fs from 'fs/promises' import path from 'path' import { app } from 'electron' +const USER_DATA_STRING = '__DEFAULT_USER_DATA__' + export default class PluginConfig { constructor(defaultPlugin) { this.defaultPlugin = defaultPlugin - this.configPath = path.join(app.getPath('userData'), 'config.json') } + // Helper to replace placeholders with dynamic values, recursively + _resolveDefaults(config) { + if (Array.isArray(config)) { + return config.map((item) => this._resolveDefaults(item)) + } else if (config && typeof config === 'object') { + const resolved = {} + for (const [key, value] of Object.entries(config)) { + resolved[key] = this._resolveDefaults(value) + } + return resolved + } else if ( + typeof config === 'string' && + config.includes(USER_DATA_STRING) + ) { + return config.replace(USER_DATA_STRING, app.getPath('userData')) + } else { + return config + } + } + async load() { let parsed @@ -32,6 +53,9 @@ export default class PluginConfig { } await this.write(parsed) + } else { + // Ensure any "__DEFAULT_USER_DATA__" values are resolved on load + parsed.adapterConfig = this._resolveDefaults(parsed.adapterConfig) } return parsed @@ -43,9 +67,15 @@ export default class PluginConfig { // Ensure directory exists await fs.mkdir(dir, { recursive: true }) + // Resolve defaults before writing + const resolvedConfig = { + ...configObject, + adapterConfig: this._resolveDefaults(configObject.adapterConfig), + } + await fs.writeFile( this.configPath, - JSON.stringify(configObject, null, 2), + JSON.stringify(resolvedConfig, null, 2), 'utf8', ) } diff --git a/src/main/index.js b/src/main/index.js index b3ce091..e36c037 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -1,7 +1,7 @@ import { electronApp, optimizer, is } from '@electron-toolkit/utils' import { app, shell, BrowserWindow, ipcMain } from 'electron' +import filesystemPlugin from 'takerofnotes-plugin-filesystem' import PluginRegistry from './core/PluginRegistry.js' -import filesystemPlugin from './plugins/filesystem' import PluginConfig from './core/PluginConfig.js' import NotesAPI from './core/NotesAPI.js' import { join } from 'path' @@ -84,7 +84,8 @@ app.whenReady().then(async () => { const registry = new PluginRegistry() // Register built-in plugins - registry.register(filesystemPlugin) + // TODO figure out why export is under default + registry.register(filesystemPlugin.default) // Pull plugin config const config = await new PluginConfig(filesystemPlugin).load() diff --git a/src/main/notesAPI.js b/src/main/notesAPI.js deleted file mode 100644 index 5951f00..0000000 --- a/src/main/notesAPI.js +++ /dev/null @@ -1,159 +0,0 @@ -import fs from 'fs/promises' -import path from 'path' -import { app } from 'electron' -import matter from 'gray-matter' -import { Index } from 'flexsearch' -import crypto from 'crypto' - -export default class NotesAPI { - constructor() { - this.notesDir = path.join(app.getPath('userData'), 'notes') - this.notesCache = new Map() - - this.index = new Index({ - tokenize: 'tolerant', - resolution: 9, - }) - } - - async init() { - await fs.mkdir(this.notesDir, { recursive: true }) - await this._loadAllNotes() - } - - async _loadAllNotes() { - const files = await fs.readdir(this.notesDir) - - for (const file of files) { - if (!file.endsWith('.md')) continue - - const fullPath = path.join(this.notesDir, file) - const raw = await fs.readFile(fullPath, 'utf8') - const parsed = matter(raw) - - const note = { - ...parsed.data, - content: parsed.content, - } - - this.notesCache.set(note.id, note) - this.index.add(note.id, note.title + note.content) - } - } - - async _writeNoteFile(note) { - const filePath = path.join(this.notesDir, `${note.id}.md`) - - const fileContent = matter.stringify(note.content, { - id: note.id, - title: note.title, - category: note.category ?? null, - createdAt: note.createdAt, - updatedAt: note.updatedAt, - }) - - await fs.writeFile(filePath, fileContent, 'utf8') - } - - /* ----------------------- - Public API - ------------------------*/ - getCategories() { - const categories = new Set() - - for (const note of this.notesCache.values()) { - if (note.category) { - categories.add(note.category) - } - } - - return Array.from(categories).sort() - } - - getCategoryNotes(categoryName) { - return Array.from(this.notesCache.values()) - .filter((n) => n.category === categoryName) - .sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt)) - } - - getNote(id) { - return this.notesCache.get(id) ?? null - } - - async createNote(metadata = {}, content = '') { - const id = crypto.randomUUID() - const now = new Date().toISOString() - - const note = { - id, - title: metadata.title || 'Untitled', - category: metadata.category || null, - createdAt: now, - updatedAt: now, - content, - } - - console.log(note) - - this.notesCache.set(id, note) - this.index.add(id, note.title + '\n' + content) - - await this._writeNoteFile(note) - - return note - } - - async deleteNote(id) { - const filePath = path.join(this.notesDir, `${id}.md`) - await fs.unlink(filePath) - this.notesCache.delete(id) - this.index.remove(id) - } - - async updateNote(id, content) { - const note = this.notesCache.get(id) - if (!note) throw new Error('Note not found') - - note.content = content - note.updatedAt = new Date().toISOString() - - this.index.update(id, note.title + '\n' + content) - - await this._writeNoteFile(note) - - return note - } - - async updateNoteMetadata(id, updates = {}) { - const note = this.notesCache.get(id) - if (!note) throw new Error('Note not found') - - const allowedFields = ['title', 'category'] - for (const key of Object.keys(updates)) { - if (!allowedFields.includes(key)) { - throw new Error(`Invalid metadata field: ${key}`) - } - } - - if (updates.title !== undefined) { - note.title = updates.title - } - - if (updates.category !== undefined) { - note.category = updates.category - } - - note.updatedAt = new Date().toISOString() - - this.index.update(id, note.title + '\n' + note.content) - - await this._writeNoteFile(note) - - return note - } - - search(query) { - const ids = this.index.search(query) - return ids.map((id) => this.notesCache.get(id)) - } -} diff --git a/src/main/plugins/filesystem/FileSystemAdapter.js b/src/main/plugins/filesystem/FileSystemAdapter.js deleted file mode 100644 index 2c1d1a2..0000000 --- a/src/main/plugins/filesystem/FileSystemAdapter.js +++ /dev/null @@ -1,65 +0,0 @@ -import BaseNotesAdapter from '../../core/BaseNotesAdapter.js' -import matter from 'gray-matter' -import fs from 'fs/promises' -import path from 'path' - -export default class FileSystemNotesAdapter extends BaseNotesAdapter { - constructor(config) { - super() - - for (const field in config) { - this[field] = config[field] - } - } - - async init() { - await fs.mkdir(this.notesDir, { recursive: true }) - } - - async getAll() { - const files = await fs.readdir(this.notesDir) - const notes = [] - - for (const file of files) { - if (!file.endsWith('.md')) continue - - const fullPath = path.join(this.notesDir, file) - const raw = await fs.readFile(fullPath, 'utf8') - const parsed = matter(raw) - - notes.push({ - ...parsed.data, - content: parsed.content, - }) - } - - return notes - } - - async create(note) { - await this._write(note) - } - - async update(note) { - await this._write(note) - } - - async delete(id) { - const filePath = path.join(this.notesDir, `${id}.md`) - await fs.unlink(filePath) - } - - async _write(note) { - const filePath = path.join(this.notesDir, `${note.id}.md`) - - const fileContent = matter.stringify(note.content, { - id: note.id, - title: note.title, - category: note.category ?? null, - createdAt: note.createdAt, - updatedAt: note.updatedAt, - }) - - await fs.writeFile(filePath, fileContent, 'utf8') - } -} diff --git a/src/main/plugins/filesystem/index.js b/src/main/plugins/filesystem/index.js deleted file mode 100644 index 3b246c5..0000000 --- a/src/main/plugins/filesystem/index.js +++ /dev/null @@ -1,24 +0,0 @@ -import path from 'path' -import { app } from 'electron' -import FileSystemAdapter from './FileSystemAdapter.js' - -export default { - id: 'filesystem', - name: 'Local Filesystem', - description: 'Stores notes as markdown files locally.', - version: '1.0.0', - - configSchema: [ - { - key: 'notesDir', - label: 'Notes Directory', - type: 'directory', - default: path.join(app.getPath('userData'), 'notes'), - required: true, - }, - ], - - createAdapter(config) { - return new FileSystemAdapter(config) - }, -}