From aa0ba69c7669edeef84b1c24c79407ee12644a77 Mon Sep 17 00:00:00 2001 From: Snowsune Date: Wed, 15 Oct 2025 15:52:16 -0400 Subject: [PATCH] Experimental moji-maker! --- .github/workflows/build_ghcr.yml | 28 +- apps/moji_maker/__init__.py | 0 apps/moji_maker/apps.py | 6 + apps/moji_maker/migrations/__init__.py | 0 .../static/moji_maker/base_heart.png | Bin 0 -> 38838 bytes .../static/moji_maker/css/bundle.css | 1 + .../moji_maker/static/moji_maker/js/bundle.js | 439 ++++++++++++++++++ .../static/moji_maker/js/bundle.js.map | 1 + apps/moji_maker/svelte/.gitignore | 4 + apps/moji_maker/svelte/build.sh | 2 + apps/moji_maker/svelte/package-lock.json | 313 +++++++++++++ apps/moji_maker/svelte/package.json | 18 + apps/moji_maker/svelte/rollup.config.js | 17 + apps/moji_maker/svelte/src/App.svelte | 36 ++ apps/moji_maker/svelte/src/main.js | 7 + .../templates/moji_maker/index.html | 13 + apps/moji_maker/urls.py | 8 + apps/moji_maker/views.py | 5 + snowsune/settings.py | 1 + snowsune/urls.py | 1 + 20 files changed, 899 insertions(+), 1 deletion(-) create mode 100644 apps/moji_maker/__init__.py create mode 100644 apps/moji_maker/apps.py create mode 100644 apps/moji_maker/migrations/__init__.py create mode 100644 apps/moji_maker/static/moji_maker/base_heart.png create mode 100644 apps/moji_maker/static/moji_maker/css/bundle.css create mode 100644 apps/moji_maker/static/moji_maker/js/bundle.js create mode 100644 apps/moji_maker/static/moji_maker/js/bundle.js.map create mode 100644 apps/moji_maker/svelte/.gitignore create mode 100755 apps/moji_maker/svelte/build.sh create mode 100644 apps/moji_maker/svelte/package-lock.json create mode 100644 apps/moji_maker/svelte/package.json create mode 100644 apps/moji_maker/svelte/rollup.config.js create mode 100644 apps/moji_maker/svelte/src/App.svelte create mode 100644 apps/moji_maker/svelte/src/main.js create mode 100644 apps/moji_maker/templates/moji_maker/index.html create mode 100644 apps/moji_maker/urls.py create mode 100644 apps/moji_maker/views.py diff --git a/.github/workflows/build_ghcr.yml b/.github/workflows/build_ghcr.yml index cd1052b..2b5bfe8 100644 --- a/.github/workflows/build_ghcr.yml +++ b/.github/workflows/build_ghcr.yml @@ -37,12 +37,25 @@ jobs: with: python-version: "3.13" - - name: Install dependencies + - name: Install Python dependencies run: | python -m pip install --upgrade pip pip install pipenv pipenv install --dev # Install dev dependencies from Pipfile + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + cache: 'npm' + cache-dependency-path: 'apps/moji_maker/svelte/package-lock.json' + + - name: Install Node dependencies and build Svelte + run: | + cd apps/moji_maker/svelte + npm ci + npm run build + - name: Run tests for ${{ matrix.test_target || 'all apps' }} run: | if [ -n "${{ matrix.test_target }}" ]; then @@ -126,6 +139,19 @@ jobs: # Done! echo "Generated Path: ${{ env.PACKAGE_PATH }} and tag: ${{ env.SANITIZED_BRANCH }}" + - name: Setup Node.js for Docker build + uses: actions/setup-node@v4 + with: + node-version: '18' + cache: 'npm' + cache-dependency-path: 'apps/moji_maker/svelte/package-lock.json' + + - name: Build Svelte for production + run: | + cd apps/moji_maker/svelte + npm ci + npm run build + - name: Inject Git commit into the build run: | echo "GIT_COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV diff --git a/apps/moji_maker/__init__.py b/apps/moji_maker/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/moji_maker/apps.py b/apps/moji_maker/apps.py new file mode 100644 index 0000000..a37a128 --- /dev/null +++ b/apps/moji_maker/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MojiMakerConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "apps.moji_maker" diff --git a/apps/moji_maker/migrations/__init__.py b/apps/moji_maker/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/moji_maker/static/moji_maker/base_heart.png b/apps/moji_maker/static/moji_maker/base_heart.png new file mode 100644 index 0000000000000000000000000000000000000000..272b2995ea8c4405db70808b71b370fadebd9fd1 GIT binary patch literal 38838 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 fk6rDU8yXSEgZ&yhpN4?fedzWo0HXN8i9 literal 0 HcmV?d00001 diff --git a/apps/moji_maker/static/moji_maker/css/bundle.css b/apps/moji_maker/static/moji_maker/css/bundle.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/apps/moji_maker/static/moji_maker/css/bundle.css @@ -0,0 +1 @@ + diff --git a/apps/moji_maker/static/moji_maker/js/bundle.js b/apps/moji_maker/static/moji_maker/js/bundle.js new file mode 100644 index 0000000..418558f --- /dev/null +++ b/apps/moji_maker/static/moji_maker/js/bundle.js @@ -0,0 +1,439 @@ +var app = (function () { + 'use strict'; + + function noop() { } + function run(fn) { + return fn(); + } + function blank_object() { + return Object.create(null); + } + function run_all(fns) { + fns.forEach(run); + } + function is_function(thing) { + return typeof thing === 'function'; + } + function safe_not_equal(a, b) { + return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function'); + } + function is_empty(obj) { + return Object.keys(obj).length === 0; + } + function insert(target, node, anchor) { + target.insertBefore(node, anchor || null); + } + function detach(node) { + if (node.parentNode) { + node.parentNode.removeChild(node); + } + } + function element(name) { + return document.createElement(name); + } + function text(data) { + return document.createTextNode(data); + } + function space() { + return text(' '); + } + function listen(node, event, handler, options) { + node.addEventListener(event, handler, options); + return () => node.removeEventListener(event, handler, options); + } + function attr(node, attribute, value) { + if (value == null) + node.removeAttribute(attribute); + else if (node.getAttribute(attribute) !== value) + node.setAttribute(attribute, value); + } + function children(element) { + return Array.from(element.childNodes); + } + function set_input_value(input, value) { + input.value = value == null ? '' : value; + } + + let current_component; + function set_current_component(component) { + current_component = component; + } + function get_current_component() { + if (!current_component) + throw new Error('Function called outside component initialization'); + return current_component; + } + /** + * The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM. + * It must be called during the component's initialisation (but doesn't need to live *inside* the component; + * it can be called from an external module). + * + * `onMount` does not run inside a [server-side component](/docs#run-time-server-side-component-api). + * + * https://svelte.dev/docs#run-time-svelte-onmount + */ + function onMount(fn) { + get_current_component().$$.on_mount.push(fn); + } + + const dirty_components = []; + const binding_callbacks = []; + let render_callbacks = []; + const flush_callbacks = []; + const resolved_promise = /* @__PURE__ */ Promise.resolve(); + let update_scheduled = false; + function schedule_update() { + if (!update_scheduled) { + update_scheduled = true; + resolved_promise.then(flush); + } + } + function add_render_callback(fn) { + render_callbacks.push(fn); + } + // flush() calls callbacks in this order: + // 1. All beforeUpdate callbacks, in order: parents before children + // 2. All bind:this callbacks, in reverse order: children before parents. + // 3. All afterUpdate callbacks, in order: parents before children. EXCEPT + // for afterUpdates called during the initial onMount, which are called in + // reverse order: children before parents. + // Since callbacks might update component values, which could trigger another + // call to flush(), the following steps guard against this: + // 1. During beforeUpdate, any updated components will be added to the + // dirty_components array and will cause a reentrant call to flush(). Because + // the flush index is kept outside the function, the reentrant call will pick + // up where the earlier call left off and go through all dirty components. The + // current_component value is saved and restored so that the reentrant call will + // not interfere with the "parent" flush() call. + // 2. bind:this callbacks cannot trigger new flush() calls. + // 3. During afterUpdate, any updated components will NOT have their afterUpdate + // callback called a second time; the seen_callbacks set, outside the flush() + // function, guarantees this behavior. + const seen_callbacks = new Set(); + let flushidx = 0; // Do *not* move this inside the flush() function + function flush() { + // Do not reenter flush while dirty components are updated, as this can + // result in an infinite loop. Instead, let the inner flush handle it. + // Reentrancy is ok afterwards for bindings etc. + if (flushidx !== 0) { + return; + } + const saved_component = current_component; + do { + // first, call beforeUpdate functions + // and update components + try { + while (flushidx < dirty_components.length) { + const component = dirty_components[flushidx]; + flushidx++; + set_current_component(component); + update(component.$$); + } + } + catch (e) { + // reset dirty state to not end up in a deadlocked state and then rethrow + dirty_components.length = 0; + flushidx = 0; + throw e; + } + set_current_component(null); + dirty_components.length = 0; + flushidx = 0; + while (binding_callbacks.length) + binding_callbacks.pop()(); + // then, once components are updated, call + // afterUpdate functions. This may cause + // subsequent updates... + for (let i = 0; i < render_callbacks.length; i += 1) { + const callback = render_callbacks[i]; + if (!seen_callbacks.has(callback)) { + // ...so guard against infinite loops + seen_callbacks.add(callback); + callback(); + } + } + render_callbacks.length = 0; + } while (dirty_components.length); + while (flush_callbacks.length) { + flush_callbacks.pop()(); + } + update_scheduled = false; + seen_callbacks.clear(); + set_current_component(saved_component); + } + function update($$) { + if ($$.fragment !== null) { + $$.update(); + run_all($$.before_update); + const dirty = $$.dirty; + $$.dirty = [-1]; + $$.fragment && $$.fragment.p($$.ctx, dirty); + $$.after_update.forEach(add_render_callback); + } + } + /** + * Useful for example to execute remaining `afterUpdate` callbacks before executing `destroy`. + */ + function flush_render_callbacks(fns) { + const filtered = []; + const targets = []; + render_callbacks.forEach((c) => fns.indexOf(c) === -1 ? filtered.push(c) : targets.push(c)); + targets.forEach((c) => c()); + render_callbacks = filtered; + } + const outroing = new Set(); + function transition_in(block, local) { + if (block && block.i) { + outroing.delete(block); + block.i(local); + } + } + function mount_component(component, target, anchor, customElement) { + const { fragment, after_update } = component.$$; + fragment && fragment.m(target, anchor); + if (!customElement) { + // onMount happens before the initial afterUpdate + add_render_callback(() => { + const new_on_destroy = component.$$.on_mount.map(run).filter(is_function); + // if the component was destroyed immediately + // it will update the `$$.on_destroy` reference to `null`. + // the destructured on_destroy may still reference to the old array + if (component.$$.on_destroy) { + component.$$.on_destroy.push(...new_on_destroy); + } + else { + // Edge case - component was destroyed immediately, + // most likely as a result of a binding initialising + run_all(new_on_destroy); + } + component.$$.on_mount = []; + }); + } + after_update.forEach(add_render_callback); + } + function destroy_component(component, detaching) { + const $$ = component.$$; + if ($$.fragment !== null) { + flush_render_callbacks($$.after_update); + run_all($$.on_destroy); + $$.fragment && $$.fragment.d(detaching); + // TODO null out other refs, including component.$$ (but need to + // preserve final state?) + $$.on_destroy = $$.fragment = null; + $$.ctx = []; + } + } + function make_dirty(component, i) { + if (component.$$.dirty[0] === -1) { + dirty_components.push(component); + schedule_update(); + component.$$.dirty.fill(0); + } + component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31)); + } + function init(component, options, instance, create_fragment, not_equal, props, append_styles, dirty = [-1]) { + const parent_component = current_component; + set_current_component(component); + const $$ = component.$$ = { + fragment: null, + ctx: [], + // state + props, + update: noop, + not_equal, + bound: blank_object(), + // lifecycle + on_mount: [], + on_destroy: [], + on_disconnect: [], + before_update: [], + after_update: [], + context: new Map(options.context || (parent_component ? parent_component.$$.context : [])), + // everything else + callbacks: blank_object(), + dirty, + skip_bound: false, + root: options.target || parent_component.$$.root + }; + append_styles && append_styles($$.root); + let ready = false; + $$.ctx = instance + ? instance(component, options.props || {}, (i, ret, ...rest) => { + const value = rest.length ? rest[0] : ret; + if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) { + if (!$$.skip_bound && $$.bound[i]) + $$.bound[i](value); + if (ready) + make_dirty(component, i); + } + return ret; + }) + : []; + $$.update(); + ready = true; + run_all($$.before_update); + // `false` as a special case of no DOM component + $$.fragment = create_fragment ? create_fragment($$.ctx) : false; + if (options.target) { + if (options.hydrate) { + const nodes = children(options.target); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + $$.fragment && $$.fragment.l(nodes); + nodes.forEach(detach); + } + else { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + $$.fragment && $$.fragment.c(); + } + if (options.intro) + transition_in(component.$$.fragment); + mount_component(component, options.target, options.anchor, options.customElement); + flush(); + } + set_current_component(parent_component); + } + /** + * Base class for Svelte components. Used when dev=false. + */ + class SvelteComponent { + $destroy() { + destroy_component(this, 1); + this.$destroy = noop; + } + $on(type, callback) { + if (!is_function(callback)) { + return noop; + } + const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = [])); + callbacks.push(callback); + return () => { + const index = callbacks.indexOf(callback); + if (index !== -1) + callbacks.splice(index, 1); + }; + } + $set($$props) { + if (this.$$set && !is_empty($$props)) { + this.$$.skip_bound = true; + this.$$set($$props); + this.$$.skip_bound = false; + } + } + } + + /* src/App.svelte generated by Svelte v3.59.2 */ + + function create_fragment(ctx) { + let canvas_1; + let t; + let input; + let mounted; + let dispose; + + return { + c() { + canvas_1 = element("canvas"); + t = space(); + input = element("input"); + attr(canvas_1, "width", "256"); + attr(canvas_1, "height", "256"); + attr(input, "type", "color"); + }, + m(target, anchor) { + insert(target, canvas_1, anchor); + /*canvas_1_binding*/ ctx[3](canvas_1); + insert(target, t, anchor); + insert(target, input, anchor); + set_input_value(input, /*colors*/ ctx[1].primary); + + if (!mounted) { + dispose = [ + listen(input, "input", /*input_input_handler*/ ctx[4]), + listen(input, "change", /*update*/ ctx[2]) + ]; + + mounted = true; + } + }, + p(ctx, [dirty]) { + if (dirty & /*colors*/ 2) { + set_input_value(input, /*colors*/ ctx[1].primary); + } + }, + i: noop, + o: noop, + d(detaching) { + if (detaching) detach(canvas_1); + /*canvas_1_binding*/ ctx[3](null); + if (detaching) detach(t); + if (detaching) detach(input); + mounted = false; + run_all(dispose); + } + }; + } + + function instance($$self, $$props, $$invalidate) { + let canvas; + let colors = { primary: "#ff6b6b" }; + + onMount(() => { + const app = document.getElementById("moji-maker-app"); + const img = new Image(); + img.src = app.getAttribute("data-heart-url"); + + img.onload = () => { + const ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0, 256, 256); + const data = ctx.getImageData(0, 0, 256, 256); + + for (let i = 0; i < data.data.length; i += 4) { + if (data.data[i + 3] === 0) continue; // skip transparent + + if (data.data[i] > 100) { + // if reddish + const hex = colors.primary; + + data.data[i] = parseInt(hex.slice(1, 3), 16); + data.data[i + 1] = parseInt(hex.slice(3, 5), 16); + data.data[i + 2] = parseInt(hex.slice(5, 7), 16); + } + } + + ctx.putImageData(data, 0, 0); + }; + }); + + function update() { + onMount(); // re-run on color change + } + + function canvas_1_binding($$value) { + binding_callbacks[$$value ? 'unshift' : 'push'](() => { + canvas = $$value; + $$invalidate(0, canvas); + }); + } + + function input_input_handler() { + colors.primary = this.value; + $$invalidate(1, colors); + } + + return [canvas, colors, update, canvas_1_binding, input_input_handler]; + } + + class App extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance, create_fragment, safe_not_equal, {}); + } + } + + const app = new App({ + target: document.getElementById('moji-maker-app'), + }); + + return app; + +})(); diff --git a/apps/moji_maker/static/moji_maker/js/bundle.js.map b/apps/moji_maker/static/moji_maker/js/bundle.js.map new file mode 100644 index 0000000..3a02cec --- /dev/null +++ b/apps/moji_maker/static/moji_maker/js/bundle.js.map @@ -0,0 +1 @@ +{"version":3,"file":"bundle.js","sources":["../../../svelte/node_modules/svelte/internal/index.mjs","../../../svelte/src/App.svelte","../../../svelte/src/main.js"],"sourcesContent":["function noop() { }\nconst identity = x => x;\nfunction assign(tar, src) {\n // @ts-ignore\n for (const k in src)\n tar[k] = src[k];\n return tar;\n}\n// Adapted from https://github.com/then/is-promise/blob/master/index.js\n// Distributed under MIT License https://github.com/then/is-promise/blob/master/LICENSE\nfunction is_promise(value) {\n return !!value && (typeof value === 'object' || typeof value === 'function') && typeof value.then === 'function';\n}\nfunction add_location(element, file, line, column, char) {\n element.__svelte_meta = {\n loc: { file, line, column, char }\n };\n}\nfunction run(fn) {\n return fn();\n}\nfunction blank_object() {\n return Object.create(null);\n}\nfunction run_all(fns) {\n fns.forEach(run);\n}\nfunction is_function(thing) {\n return typeof thing === 'function';\n}\nfunction safe_not_equal(a, b) {\n return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');\n}\nlet src_url_equal_anchor;\nfunction src_url_equal(element_src, url) {\n if (!src_url_equal_anchor) {\n src_url_equal_anchor = document.createElement('a');\n }\n src_url_equal_anchor.href = url;\n return element_src === src_url_equal_anchor.href;\n}\nfunction not_equal(a, b) {\n return a != a ? b == b : a !== b;\n}\nfunction is_empty(obj) {\n return Object.keys(obj).length === 0;\n}\nfunction validate_store(store, name) {\n if (store != null && typeof store.subscribe !== 'function') {\n throw new Error(`'${name}' is not a store with a 'subscribe' method`);\n }\n}\nfunction subscribe(store, ...callbacks) {\n if (store == null) {\n return noop;\n }\n const unsub = store.subscribe(...callbacks);\n return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub;\n}\nfunction get_store_value(store) {\n let value;\n subscribe(store, _ => value = _)();\n return value;\n}\nfunction component_subscribe(component, store, callback) {\n component.$$.on_destroy.push(subscribe(store, callback));\n}\nfunction create_slot(definition, ctx, $$scope, fn) {\n if (definition) {\n const slot_ctx = get_slot_context(definition, ctx, $$scope, fn);\n return definition[0](slot_ctx);\n }\n}\nfunction get_slot_context(definition, ctx, $$scope, fn) {\n return definition[1] && fn\n ? assign($$scope.ctx.slice(), definition[1](fn(ctx)))\n : $$scope.ctx;\n}\nfunction get_slot_changes(definition, $$scope, dirty, fn) {\n if (definition[2] && fn) {\n const lets = definition[2](fn(dirty));\n if ($$scope.dirty === undefined) {\n return lets;\n }\n if (typeof lets === 'object') {\n const merged = [];\n const len = Math.max($$scope.dirty.length, lets.length);\n for (let i = 0; i < len; i += 1) {\n merged[i] = $$scope.dirty[i] | lets[i];\n }\n return merged;\n }\n return $$scope.dirty | lets;\n }\n return $$scope.dirty;\n}\nfunction update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn) {\n if (slot_changes) {\n const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn);\n slot.p(slot_context, slot_changes);\n }\n}\nfunction update_slot(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_context_fn) {\n const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn);\n update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn);\n}\nfunction get_all_dirty_from_scope($$scope) {\n if ($$scope.ctx.length > 32) {\n const dirty = [];\n const length = $$scope.ctx.length / 32;\n for (let i = 0; i < length; i++) {\n dirty[i] = -1;\n }\n return dirty;\n }\n return -1;\n}\nfunction exclude_internal_props(props) {\n const result = {};\n for (const k in props)\n if (k[0] !== '$')\n result[k] = props[k];\n return result;\n}\nfunction compute_rest_props(props, keys) {\n const rest = {};\n keys = new Set(keys);\n for (const k in props)\n if (!keys.has(k) && k[0] !== '$')\n rest[k] = props[k];\n return rest;\n}\nfunction compute_slots(slots) {\n const result = {};\n for (const key in slots) {\n result[key] = true;\n }\n return result;\n}\nfunction once(fn) {\n let ran = false;\n return function (...args) {\n if (ran)\n return;\n ran = true;\n fn.call(this, ...args);\n };\n}\nfunction null_to_empty(value) {\n return value == null ? '' : value;\n}\nfunction set_store_value(store, ret, value) {\n store.set(value);\n return ret;\n}\nconst has_prop = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);\nfunction action_destroyer(action_result) {\n return action_result && is_function(action_result.destroy) ? action_result.destroy : noop;\n}\nfunction split_css_unit(value) {\n const split = typeof value === 'string' && value.match(/^\\s*(-?[\\d.]+)([^\\s]*)\\s*$/);\n return split ? [parseFloat(split[1]), split[2] || 'px'] : [value, 'px'];\n}\nconst contenteditable_truthy_values = ['', true, 1, 'true', 'contenteditable'];\n\nconst is_client = typeof window !== 'undefined';\nlet now = is_client\n ? () => window.performance.now()\n : () => Date.now();\nlet raf = is_client ? cb => requestAnimationFrame(cb) : noop;\n// used internally for testing\nfunction set_now(fn) {\n now = fn;\n}\nfunction set_raf(fn) {\n raf = fn;\n}\n\nconst tasks = new Set();\nfunction run_tasks(now) {\n tasks.forEach(task => {\n if (!task.c(now)) {\n tasks.delete(task);\n task.f();\n }\n });\n if (tasks.size !== 0)\n raf(run_tasks);\n}\n/**\n * For testing purposes only!\n */\nfunction clear_loops() {\n tasks.clear();\n}\n/**\n * Creates a new task that runs on each raf frame\n * until it returns a falsy value or is aborted\n */\nfunction loop(callback) {\n let task;\n if (tasks.size === 0)\n raf(run_tasks);\n return {\n promise: new Promise(fulfill => {\n tasks.add(task = { c: callback, f: fulfill });\n }),\n abort() {\n tasks.delete(task);\n }\n };\n}\n\nconst globals = (typeof window !== 'undefined'\n ? window\n : typeof globalThis !== 'undefined'\n ? globalThis\n : global);\n\n/**\n * Resize observer singleton.\n * One listener per element only!\n * https://groups.google.com/a/chromium.org/g/blink-dev/c/z6ienONUb5A/m/F5-VcUZtBAAJ\n */\nclass ResizeObserverSingleton {\n constructor(options) {\n this.options = options;\n this._listeners = 'WeakMap' in globals ? new WeakMap() : undefined;\n }\n observe(element, listener) {\n this._listeners.set(element, listener);\n this._getObserver().observe(element, this.options);\n return () => {\n this._listeners.delete(element);\n this._observer.unobserve(element); // this line can probably be removed\n };\n }\n _getObserver() {\n var _a;\n return (_a = this._observer) !== null && _a !== void 0 ? _a : (this._observer = new ResizeObserver((entries) => {\n var _a;\n for (const entry of entries) {\n ResizeObserverSingleton.entries.set(entry.target, entry);\n (_a = this._listeners.get(entry.target)) === null || _a === void 0 ? void 0 : _a(entry);\n }\n }));\n }\n}\n// Needs to be written like this to pass the tree-shake-test\nResizeObserverSingleton.entries = 'WeakMap' in globals ? new WeakMap() : undefined;\n\n// Track which nodes are claimed during hydration. Unclaimed nodes can then be removed from the DOM\n// at the end of hydration without touching the remaining nodes.\nlet is_hydrating = false;\nfunction start_hydrating() {\n is_hydrating = true;\n}\nfunction end_hydrating() {\n is_hydrating = false;\n}\nfunction upper_bound(low, high, key, value) {\n // Return first index of value larger than input value in the range [low, high)\n while (low < high) {\n const mid = low + ((high - low) >> 1);\n if (key(mid) <= value) {\n low = mid + 1;\n }\n else {\n high = mid;\n }\n }\n return low;\n}\nfunction init_hydrate(target) {\n if (target.hydrate_init)\n return;\n target.hydrate_init = true;\n // We know that all children have claim_order values since the unclaimed have been detached if target is not \n let children = target.childNodes;\n // If target is , there may be children without claim_order\n if (target.nodeName === 'HEAD') {\n const myChildren = [];\n for (let i = 0; i < children.length; i++) {\n const node = children[i];\n if (node.claim_order !== undefined) {\n myChildren.push(node);\n }\n }\n children = myChildren;\n }\n /*\n * Reorder claimed children optimally.\n * We can reorder claimed children optimally by finding the longest subsequence of\n * nodes that are already claimed in order and only moving the rest. The longest\n * subsequence of nodes that are claimed in order can be found by\n * computing the longest increasing subsequence of .claim_order values.\n *\n * This algorithm is optimal in generating the least amount of reorder operations\n * possible.\n *\n * Proof:\n * We know that, given a set of reordering operations, the nodes that do not move\n * always form an increasing subsequence, since they do not move among each other\n * meaning that they must be already ordered among each other. Thus, the maximal\n * set of nodes that do not move form a longest increasing subsequence.\n */\n // Compute longest increasing subsequence\n // m: subsequence length j => index k of smallest value that ends an increasing subsequence of length j\n const m = new Int32Array(children.length + 1);\n // Predecessor indices + 1\n const p = new Int32Array(children.length);\n m[0] = -1;\n let longest = 0;\n for (let i = 0; i < children.length; i++) {\n const current = children[i].claim_order;\n // Find the largest subsequence length such that it ends in a value less than our current value\n // upper_bound returns first greater value, so we subtract one\n // with fast path for when we are on the current longest subsequence\n const seqLen = ((longest > 0 && children[m[longest]].claim_order <= current) ? longest + 1 : upper_bound(1, longest, idx => children[m[idx]].claim_order, current)) - 1;\n p[i] = m[seqLen] + 1;\n const newLen = seqLen + 1;\n // We can guarantee that current is the smallest value. Otherwise, we would have generated a longer sequence.\n m[newLen] = i;\n longest = Math.max(newLen, longest);\n }\n // The longest increasing subsequence of nodes (initially reversed)\n const lis = [];\n // The rest of the nodes, nodes that will be moved\n const toMove = [];\n let last = children.length - 1;\n for (let cur = m[longest] + 1; cur != 0; cur = p[cur - 1]) {\n lis.push(children[cur - 1]);\n for (; last >= cur; last--) {\n toMove.push(children[last]);\n }\n last--;\n }\n for (; last >= 0; last--) {\n toMove.push(children[last]);\n }\n lis.reverse();\n // We sort the nodes being moved to guarantee that their insertion order matches the claim order\n toMove.sort((a, b) => a.claim_order - b.claim_order);\n // Finally, we move the nodes\n for (let i = 0, j = 0; i < toMove.length; i++) {\n while (j < lis.length && toMove[i].claim_order >= lis[j].claim_order) {\n j++;\n }\n const anchor = j < lis.length ? lis[j] : null;\n target.insertBefore(toMove[i], anchor);\n }\n}\nfunction append(target, node) {\n target.appendChild(node);\n}\nfunction append_styles(target, style_sheet_id, styles) {\n const append_styles_to = get_root_for_style(target);\n if (!append_styles_to.getElementById(style_sheet_id)) {\n const style = element('style');\n style.id = style_sheet_id;\n style.textContent = styles;\n append_stylesheet(append_styles_to, style);\n }\n}\nfunction get_root_for_style(node) {\n if (!node)\n return document;\n const root = node.getRootNode ? node.getRootNode() : node.ownerDocument;\n if (root && root.host) {\n return root;\n }\n return node.ownerDocument;\n}\nfunction append_empty_stylesheet(node) {\n const style_element = element('style');\n append_stylesheet(get_root_for_style(node), style_element);\n return style_element.sheet;\n}\nfunction append_stylesheet(node, style) {\n append(node.head || node, style);\n return style.sheet;\n}\nfunction append_hydration(target, node) {\n if (is_hydrating) {\n init_hydrate(target);\n if ((target.actual_end_child === undefined) || ((target.actual_end_child !== null) && (target.actual_end_child.parentNode !== target))) {\n target.actual_end_child = target.firstChild;\n }\n // Skip nodes of undefined ordering\n while ((target.actual_end_child !== null) && (target.actual_end_child.claim_order === undefined)) {\n target.actual_end_child = target.actual_end_child.nextSibling;\n }\n if (node !== target.actual_end_child) {\n // We only insert if the ordering of this node should be modified or the parent node is not target\n if (node.claim_order !== undefined || node.parentNode !== target) {\n target.insertBefore(node, target.actual_end_child);\n }\n }\n else {\n target.actual_end_child = node.nextSibling;\n }\n }\n else if (node.parentNode !== target || node.nextSibling !== null) {\n target.appendChild(node);\n }\n}\nfunction insert(target, node, anchor) {\n target.insertBefore(node, anchor || null);\n}\nfunction insert_hydration(target, node, anchor) {\n if (is_hydrating && !anchor) {\n append_hydration(target, node);\n }\n else if (node.parentNode !== target || node.nextSibling != anchor) {\n target.insertBefore(node, anchor || null);\n }\n}\nfunction detach(node) {\n if (node.parentNode) {\n node.parentNode.removeChild(node);\n }\n}\nfunction destroy_each(iterations, detaching) {\n for (let i = 0; i < iterations.length; i += 1) {\n if (iterations[i])\n iterations[i].d(detaching);\n }\n}\nfunction element(name) {\n return document.createElement(name);\n}\nfunction element_is(name, is) {\n return document.createElement(name, { is });\n}\nfunction object_without_properties(obj, exclude) {\n const target = {};\n for (const k in obj) {\n if (has_prop(obj, k)\n // @ts-ignore\n && exclude.indexOf(k) === -1) {\n // @ts-ignore\n target[k] = obj[k];\n }\n }\n return target;\n}\nfunction svg_element(name) {\n return document.createElementNS('http://www.w3.org/2000/svg', name);\n}\nfunction text(data) {\n return document.createTextNode(data);\n}\nfunction space() {\n return text(' ');\n}\nfunction empty() {\n return text('');\n}\nfunction comment(content) {\n return document.createComment(content);\n}\nfunction listen(node, event, handler, options) {\n node.addEventListener(event, handler, options);\n return () => node.removeEventListener(event, handler, options);\n}\nfunction prevent_default(fn) {\n return function (event) {\n event.preventDefault();\n // @ts-ignore\n return fn.call(this, event);\n };\n}\nfunction stop_propagation(fn) {\n return function (event) {\n event.stopPropagation();\n // @ts-ignore\n return fn.call(this, event);\n };\n}\nfunction stop_immediate_propagation(fn) {\n return function (event) {\n event.stopImmediatePropagation();\n // @ts-ignore\n return fn.call(this, event);\n };\n}\nfunction self(fn) {\n return function (event) {\n // @ts-ignore\n if (event.target === this)\n fn.call(this, event);\n };\n}\nfunction trusted(fn) {\n return function (event) {\n // @ts-ignore\n if (event.isTrusted)\n fn.call(this, event);\n };\n}\nfunction attr(node, attribute, value) {\n if (value == null)\n node.removeAttribute(attribute);\n else if (node.getAttribute(attribute) !== value)\n node.setAttribute(attribute, value);\n}\n/**\n * List of attributes that should always be set through the attr method,\n * because updating them through the property setter doesn't work reliably.\n * In the example of `width`/`height`, the problem is that the setter only\n * accepts numeric values, but the attribute can also be set to a string like `50%`.\n * If this list becomes too big, rethink this approach.\n */\nconst always_set_through_set_attribute = ['width', 'height'];\nfunction set_attributes(node, attributes) {\n // @ts-ignore\n const descriptors = Object.getOwnPropertyDescriptors(node.__proto__);\n for (const key in attributes) {\n if (attributes[key] == null) {\n node.removeAttribute(key);\n }\n else if (key === 'style') {\n node.style.cssText = attributes[key];\n }\n else if (key === '__value') {\n node.value = node[key] = attributes[key];\n }\n else if (descriptors[key] && descriptors[key].set && always_set_through_set_attribute.indexOf(key) === -1) {\n node[key] = attributes[key];\n }\n else {\n attr(node, key, attributes[key]);\n }\n }\n}\nfunction set_svg_attributes(node, attributes) {\n for (const key in attributes) {\n attr(node, key, attributes[key]);\n }\n}\nfunction set_custom_element_data_map(node, data_map) {\n Object.keys(data_map).forEach((key) => {\n set_custom_element_data(node, key, data_map[key]);\n });\n}\nfunction set_custom_element_data(node, prop, value) {\n if (prop in node) {\n node[prop] = typeof node[prop] === 'boolean' && value === '' ? true : value;\n }\n else {\n attr(node, prop, value);\n }\n}\nfunction set_dynamic_element_data(tag) {\n return (/-/.test(tag)) ? set_custom_element_data_map : set_attributes;\n}\nfunction xlink_attr(node, attribute, value) {\n node.setAttributeNS('http://www.w3.org/1999/xlink', attribute, value);\n}\nfunction get_binding_group_value(group, __value, checked) {\n const value = new Set();\n for (let i = 0; i < group.length; i += 1) {\n if (group[i].checked)\n value.add(group[i].__value);\n }\n if (!checked) {\n value.delete(__value);\n }\n return Array.from(value);\n}\nfunction init_binding_group(group) {\n let _inputs;\n return {\n /* push */ p(...inputs) {\n _inputs = inputs;\n _inputs.forEach(input => group.push(input));\n },\n /* remove */ r() {\n _inputs.forEach(input => group.splice(group.indexOf(input), 1));\n }\n };\n}\nfunction init_binding_group_dynamic(group, indexes) {\n let _group = get_binding_group(group);\n let _inputs;\n function get_binding_group(group) {\n for (let i = 0; i < indexes.length; i++) {\n group = group[indexes[i]] = group[indexes[i]] || [];\n }\n return group;\n }\n function push() {\n _inputs.forEach(input => _group.push(input));\n }\n function remove() {\n _inputs.forEach(input => _group.splice(_group.indexOf(input), 1));\n }\n return {\n /* update */ u(new_indexes) {\n indexes = new_indexes;\n const new_group = get_binding_group(group);\n if (new_group !== _group) {\n remove();\n _group = new_group;\n push();\n }\n },\n /* push */ p(...inputs) {\n _inputs = inputs;\n push();\n },\n /* remove */ r: remove\n };\n}\nfunction to_number(value) {\n return value === '' ? null : +value;\n}\nfunction time_ranges_to_array(ranges) {\n const array = [];\n for (let i = 0; i < ranges.length; i += 1) {\n array.push({ start: ranges.start(i), end: ranges.end(i) });\n }\n return array;\n}\nfunction children(element) {\n return Array.from(element.childNodes);\n}\nfunction init_claim_info(nodes) {\n if (nodes.claim_info === undefined) {\n nodes.claim_info = { last_index: 0, total_claimed: 0 };\n }\n}\nfunction claim_node(nodes, predicate, processNode, createNode, dontUpdateLastIndex = false) {\n // Try to find nodes in an order such that we lengthen the longest increasing subsequence\n init_claim_info(nodes);\n const resultNode = (() => {\n // We first try to find an element after the previous one\n for (let i = nodes.claim_info.last_index; i < nodes.length; i++) {\n const node = nodes[i];\n if (predicate(node)) {\n const replacement = processNode(node);\n if (replacement === undefined) {\n nodes.splice(i, 1);\n }\n else {\n nodes[i] = replacement;\n }\n if (!dontUpdateLastIndex) {\n nodes.claim_info.last_index = i;\n }\n return node;\n }\n }\n // Otherwise, we try to find one before\n // We iterate in reverse so that we don't go too far back\n for (let i = nodes.claim_info.last_index - 1; i >= 0; i--) {\n const node = nodes[i];\n if (predicate(node)) {\n const replacement = processNode(node);\n if (replacement === undefined) {\n nodes.splice(i, 1);\n }\n else {\n nodes[i] = replacement;\n }\n if (!dontUpdateLastIndex) {\n nodes.claim_info.last_index = i;\n }\n else if (replacement === undefined) {\n // Since we spliced before the last_index, we decrease it\n nodes.claim_info.last_index--;\n }\n return node;\n }\n }\n // If we can't find any matching node, we create a new one\n return createNode();\n })();\n resultNode.claim_order = nodes.claim_info.total_claimed;\n nodes.claim_info.total_claimed += 1;\n return resultNode;\n}\nfunction claim_element_base(nodes, name, attributes, create_element) {\n return claim_node(nodes, (node) => node.nodeName === name, (node) => {\n const remove = [];\n for (let j = 0; j < node.attributes.length; j++) {\n const attribute = node.attributes[j];\n if (!attributes[attribute.name]) {\n remove.push(attribute.name);\n }\n }\n remove.forEach(v => node.removeAttribute(v));\n return undefined;\n }, () => create_element(name));\n}\nfunction claim_element(nodes, name, attributes) {\n return claim_element_base(nodes, name, attributes, element);\n}\nfunction claim_svg_element(nodes, name, attributes) {\n return claim_element_base(nodes, name, attributes, svg_element);\n}\nfunction claim_text(nodes, data) {\n return claim_node(nodes, (node) => node.nodeType === 3, (node) => {\n const dataStr = '' + data;\n if (node.data.startsWith(dataStr)) {\n if (node.data.length !== dataStr.length) {\n return node.splitText(dataStr.length);\n }\n }\n else {\n node.data = dataStr;\n }\n }, () => text(data), true // Text nodes should not update last index since it is likely not worth it to eliminate an increasing subsequence of actual elements\n );\n}\nfunction claim_space(nodes) {\n return claim_text(nodes, ' ');\n}\nfunction claim_comment(nodes, data) {\n return claim_node(nodes, (node) => node.nodeType === 8, (node) => {\n node.data = '' + data;\n return undefined;\n }, () => comment(data), true);\n}\nfunction find_comment(nodes, text, start) {\n for (let i = start; i < nodes.length; i += 1) {\n const node = nodes[i];\n if (node.nodeType === 8 /* comment node */ && node.textContent.trim() === text) {\n return i;\n }\n }\n return nodes.length;\n}\nfunction claim_html_tag(nodes, is_svg) {\n // find html opening tag\n const start_index = find_comment(nodes, 'HTML_TAG_START', 0);\n const end_index = find_comment(nodes, 'HTML_TAG_END', start_index);\n if (start_index === end_index) {\n return new HtmlTagHydration(undefined, is_svg);\n }\n init_claim_info(nodes);\n const html_tag_nodes = nodes.splice(start_index, end_index - start_index + 1);\n detach(html_tag_nodes[0]);\n detach(html_tag_nodes[html_tag_nodes.length - 1]);\n const claimed_nodes = html_tag_nodes.slice(1, html_tag_nodes.length - 1);\n for (const n of claimed_nodes) {\n n.claim_order = nodes.claim_info.total_claimed;\n nodes.claim_info.total_claimed += 1;\n }\n return new HtmlTagHydration(claimed_nodes, is_svg);\n}\nfunction set_data(text, data) {\n data = '' + data;\n if (text.data === data)\n return;\n text.data = data;\n}\nfunction set_data_contenteditable(text, data) {\n data = '' + data;\n if (text.wholeText === data)\n return;\n text.data = data;\n}\nfunction set_data_maybe_contenteditable(text, data, attr_value) {\n if (~contenteditable_truthy_values.indexOf(attr_value)) {\n set_data_contenteditable(text, data);\n }\n else {\n set_data(text, data);\n }\n}\nfunction set_input_value(input, value) {\n input.value = value == null ? '' : value;\n}\nfunction set_input_type(input, type) {\n try {\n input.type = type;\n }\n catch (e) {\n // do nothing\n }\n}\nfunction set_style(node, key, value, important) {\n if (value == null) {\n node.style.removeProperty(key);\n }\n else {\n node.style.setProperty(key, value, important ? 'important' : '');\n }\n}\nfunction select_option(select, value, mounting) {\n for (let i = 0; i < select.options.length; i += 1) {\n const option = select.options[i];\n if (option.__value === value) {\n option.selected = true;\n return;\n }\n }\n if (!mounting || value !== undefined) {\n select.selectedIndex = -1; // no option should be selected\n }\n}\nfunction select_options(select, value) {\n for (let i = 0; i < select.options.length; i += 1) {\n const option = select.options[i];\n option.selected = ~value.indexOf(option.__value);\n }\n}\nfunction select_value(select) {\n const selected_option = select.querySelector(':checked');\n return selected_option && selected_option.__value;\n}\nfunction select_multiple_value(select) {\n return [].map.call(select.querySelectorAll(':checked'), option => option.__value);\n}\n// unfortunately this can't be a constant as that wouldn't be tree-shakeable\n// so we cache the result instead\nlet crossorigin;\nfunction is_crossorigin() {\n if (crossorigin === undefined) {\n crossorigin = false;\n try {\n if (typeof window !== 'undefined' && window.parent) {\n void window.parent.document;\n }\n }\n catch (error) {\n crossorigin = true;\n }\n }\n return crossorigin;\n}\nfunction add_iframe_resize_listener(node, fn) {\n const computed_style = getComputedStyle(node);\n if (computed_style.position === 'static') {\n node.style.position = 'relative';\n }\n const iframe = element('iframe');\n iframe.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; ' +\n 'overflow: hidden; border: 0; opacity: 0; pointer-events: none; z-index: -1;');\n iframe.setAttribute('aria-hidden', 'true');\n iframe.tabIndex = -1;\n const crossorigin = is_crossorigin();\n let unsubscribe;\n if (crossorigin) {\n iframe.src = \"data:text/html,\";\n unsubscribe = listen(window, 'message', (event) => {\n if (event.source === iframe.contentWindow)\n fn();\n });\n }\n else {\n iframe.src = 'about:blank';\n iframe.onload = () => {\n unsubscribe = listen(iframe.contentWindow, 'resize', fn);\n // make sure an initial resize event is fired _after_ the iframe is loaded (which is asynchronous)\n // see https://github.com/sveltejs/svelte/issues/4233\n fn();\n };\n }\n append(node, iframe);\n return () => {\n if (crossorigin) {\n unsubscribe();\n }\n else if (unsubscribe && iframe.contentWindow) {\n unsubscribe();\n }\n detach(iframe);\n };\n}\nconst resize_observer_content_box = /* @__PURE__ */ new ResizeObserverSingleton({ box: 'content-box' });\nconst resize_observer_border_box = /* @__PURE__ */ new ResizeObserverSingleton({ box: 'border-box' });\nconst resize_observer_device_pixel_content_box = /* @__PURE__ */ new ResizeObserverSingleton({ box: 'device-pixel-content-box' });\nfunction toggle_class(element, name, toggle) {\n element.classList[toggle ? 'add' : 'remove'](name);\n}\nfunction custom_event(type, detail, { bubbles = false, cancelable = false } = {}) {\n const e = document.createEvent('CustomEvent');\n e.initCustomEvent(type, bubbles, cancelable, detail);\n return e;\n}\nfunction query_selector_all(selector, parent = document.body) {\n return Array.from(parent.querySelectorAll(selector));\n}\nfunction head_selector(nodeId, head) {\n const result = [];\n let started = 0;\n for (const node of head.childNodes) {\n if (node.nodeType === 8 /* comment node */) {\n const comment = node.textContent.trim();\n if (comment === `HEAD_${nodeId}_END`) {\n started -= 1;\n result.push(node);\n }\n else if (comment === `HEAD_${nodeId}_START`) {\n started += 1;\n result.push(node);\n }\n }\n else if (started > 0) {\n result.push(node);\n }\n }\n return result;\n}\nclass HtmlTag {\n constructor(is_svg = false) {\n this.is_svg = false;\n this.is_svg = is_svg;\n this.e = this.n = null;\n }\n c(html) {\n this.h(html);\n }\n m(html, target, anchor = null) {\n if (!this.e) {\n if (this.is_svg)\n this.e = svg_element(target.nodeName);\n /** #7364 target for