{"version":3,"file":"application.753f8e85.js","sources":["../../../app/frontend/controllers/clipboard_copy_controller.ts","../../../app/frontend/controllers/darkmode_toggle_controller.ts","../../../app/frontend/controllers/drag_and_drop_controller.ts","../../../app/frontend/controllers/file_paster_controller.ts","../../../app/frontend/controllers/file_preview_controller.ts","../../../app/frontend/controllers/flash_controller.ts","../../../app/frontend/controllers/locale_time_controller.ts","../../../app/frontend/controllers/relative_time_input_controller.ts","../../../app/frontend/controllers/tagify_controller.ts","../../../app/frontend/controllers/toggler_controller.ts","../../../app/frontend/entrypoints/application.js"],"sourcesContent":["import { Controller } from \"@hotwired/stimulus\"\n\n/*\n * Clipboard Copy\n * ==========\n *\n * Copy an anchor link or input value to the clipboard\n *\n * Actions:\n * - copy\n *\n * Target:\n * - source : element to copy the value from\n *\n * Example:\n *
\n * \n * \n *
\n */\nexport default class ClipboardCopyController extends Controller {\n declare readonly sourceTarget: HTMLElement\n static targets = [\"source\"]\n\n get valueToCopy() {\n if (\n this.sourceTarget instanceof HTMLInputElement ||\n this.sourceTarget instanceof HTMLTextAreaElement\n ) {\n return this.sourceTarget.value\n } else if (this.sourceTarget instanceof HTMLAnchorElement) {\n return this.sourceTarget.href\n }\n\n throw \"Unknown element type to copy from, should be an anchor or input!\"\n }\n\n copy(event: MouseEvent) {\n event.preventDefault()\n\n navigator.clipboard.writeText(this.valueToCopy)\n }\n}\n","import { Controller } from \"@hotwired/stimulus\"\n\nenum Theme {\n Dark = \"dark\",\n Light = \"light\",\n}\n\nconst STORAGE_KEY = \"theme\"\n\n/*\n * Darkmode Toggle\n * ==========\n *\n * Attempts to restore the users prefered darkmode setting from localstorage,\n * falling back to the user-agents prefered color scheme if unavailable.\n *\n * Adds a `dark` class to the html element if darkmode is active, and attempts to set\n * the `active` value for any child `Toggler` instances.\n *\n * Actions:\n * - flipLightSwitch\n *\n * Example:\n * \n */\nexport default class DarkmodeToggleController extends Controller {\n watcher: MediaQueryList\n\n connect() {\n this.watcher = window.matchMedia(\"(prefers-color-scheme: dark)\")\n this.watcher.addEventListener(\"change\", this.applyTheme)\n\n this.applyTheme()\n }\n\n disconnect() {\n this.watcher.removeEventListener(\"change\", this.applyTheme)\n }\n\n prefersDarkTheme = () => this.watcher.matches\n\n applyTheme = () => {\n const preferredTheme = this.prefersDarkTheme() ? Theme.Dark : Theme.Light\n const currentTheme = localStorage.getItem(STORAGE_KEY) ?? preferredTheme\n\n const isDark = currentTheme === Theme.Dark\n document.querySelector(\"html\").classList.toggle(\"dark\", isDark)\n\n this.element\n .querySelectorAll(\"[data-controller~=toggler]\")\n .forEach(target =>\n target.setAttribute(\"data-toggler-active-value\", String(isDark))\n )\n }\n\n flipLightSwitch(event: MouseEvent) {\n event.preventDefault()\n\n const stored = localStorage.getItem(STORAGE_KEY)\n\n if (stored) localStorage.removeItem(STORAGE_KEY)\n else\n localStorage.setItem(\n STORAGE_KEY,\n this.prefersDarkTheme() ? Theme.Light : Theme.Dark\n )\n\n this.applyTheme()\n }\n}\n","import { Controller } from \"@hotwired/stimulus\"\n\nexport default class DragAndDropController extends Controller {\n declare readonly inputTarget: HTMLInputElement\n static targets = [\"input\"]\n\n onDrop(event: DragEvent) {\n this.inputTarget.files = event.dataTransfer.files\n }\n\n startDragging = (event: DragEvent) => {}\n\n stopDragging = (event: DragEvent) => {}\n\n onDrag = (event: DragEvent) => {}\n}\n","import { Controller } from \"@hotwired/stimulus\"\n\nexport default class FilePasterController extends Controller {\n declare readonly inputTarget: HTMLInputElement\n static targets = [\"input\"]\n\n connect() {\n document.addEventListener(\"paste\", this.onPaste)\n }\n\n disconnect() {\n document.removeEventListener(\"paste\", this.onPaste)\n }\n\n onPaste(event: ClipboardEvent) {\n if (event.clipboardData.files.length == 0) return\n\n event.preventDefault()\n event.stopPropagation()\n\n this.inputTarget.files = event.clipboardData.files\n }\n}\n","import { Controller } from \"@hotwired/stimulus\"\n\nexport default class FilePreviewController extends Controller {\n declare readonly inputTarget: HTMLInputElement\n declare readonly imgTarget: HTMLImageElement\n static targets = [\"input\", \"img\"]\n\n connect() {}\n\n updatePreview() {\n let file = this.inputTarget.files[0]\n\n let reader = new FileReader()\n reader.onload = e => {\n this.imgTarget.src = e.target.result.toString()\n }\n\n reader.readAsDataURL(file)\n }\n}\n","import { Controller } from \"@hotwired/stimulus\"\n\nexport default class FlashController extends Controller {\n declare countdownValue: number\n declare durationValue: string\n static values = {\n duration: String,\n countdown: Number,\n }\n\n declare readonly circleTarget: SVGCircleElement\n static targets = [\"circle\"]\n\n timer: number\n circumference: number\n\n connect() {\n if (this.durationValue === \"permanent\") return\n\n this.countdownValue = parseInt(this.durationValue)\n\n this.timer = setInterval(() => this.countDown(), 1000)\n\n let radius = this.circleTarget.r.baseVal.value\n this.circumference = radius * 2 * Math.PI\n\n this.circleTarget.style.strokeDasharray = `${this.circumference} ${this.circumference}`\n this.circleTarget.style.strokeDashoffset = `${this.circumference}`\n }\n\n countDown() {\n this.countdownValue--\n\n let offset =\n this.circumference -\n (this.countdownValue / parseInt(this.durationValue)) * this.circumference\n\n this.circleTarget.style.strokeDashoffset = `${offset}`\n\n if (this.countdownValue == 0) return this.close()\n }\n\n close() {\n clearInterval(this.timer)\n this.element.remove()\n }\n}\n","import { Controller } from \"@hotwired/stimulus\"\n\nimport { DateTime } from \"luxon\"\n\n/*\n * Locale Time\n * ==========\n *\n * Translate a time tags RFC3339 formated timestamp into a\n * timezone and locale aware human format\n *\n * Example:\n * \n */\nexport default class LocaleTimeController extends Controller {\n connect() {\n const datetime = this.element.attributes.getNamedItem(\"datetime\").value\n const utc = DateTime.fromISO(datetime)\n\n this.#asHtmlElem.innerText = utc.toLocaleString(DateTime.DATETIME_MED)\n }\n\n get #asHtmlElem() {\n return this.element as HTMLElement\n }\n}\n","import { Controller } from \"@hotwired/stimulus\"\n\nimport { DateTime } from \"luxon\"\n\n/*\n * Relative Time Input\n * ==========\n *\n * Converts a UTC date input into a timezone aware input\n *\n * Target:\n * - input\n *\n * Actions:\n * - updateUtcTime\n *\n * Example:\n *
\n * \n * \n */\nexport default class RelativeTimeInputController extends Controller {\n utcInput: HTMLInputElement\n\n declare readonly inputTarget: HTMLInputElement\n static targets = [\"input\"]\n\n connect() {\n this.utcInput = this.inputTarget.cloneNode() as HTMLInputElement\n this.utcInput.type = \"hidden\"\n this.utcInput.id = this.utcInput.id + \"_utc\"\n this.utcInput.dataset.action = null\n\n this.inputTarget.name = \"\"\n this.element.insertBefore(this.utcInput, this.inputTarget)\n }\n\n updateUtcTime(event: InputEvent) {\n let local = (event.target as HTMLInputElement).value\n let utc = DateTime.fromISO(local).toUTC().toISODate()\n\n this.utcInput.value = utc\n }\n}\n","import { Controller } from \"@hotwired/stimulus\"\n\nimport Tagify from \"@yaireo/tagify\"\n\n/*\n * Tagify\n * ==========\n *\n * Hooks up an input to Tagify\n *\n * Values:\n * - allowlist\n *\n * Target:\n * - input\n *\n * Example:\n *
\n * \n * \n */\nexport default class TagifyController extends Controller {\n declare allowlistValue: string\n static values = {\n allowlist: String,\n }\n\n declare readonly inputTarget: HTMLInputElement\n static targets = [\"input\"]\n\n tagify: InstanceType\n\n connect() {\n let opts: Record = {\n originalInputValueFormat: valuesArr =>\n valuesArr.map(item => item.value).join(\",\"),\n pattern: /^[A-Za-z1-9_-\\s\\/]+$/,\n editTags: false,\n }\n\n if (this.allowlistValue)\n opts.whitelist = (this.allowlistValue || \"\").split(\",\")\n\n console.log(opts)\n\n this.tagify = new Tagify(this.inputTarget, opts)\n console.debug(this.tagify)\n }\n\n disconnect() {\n this.tagify.destroy()\n }\n}\n","import { Controller } from \"@hotwired/stimulus\"\n\n/*\n * Toggler\n * ==========\n *\n * Toggles CSS classes on targets according to the `active` value\n *\n * Each target can define a data-toggler-active-class and data-toggler-inactive-class\n * When active, each target will have it's active-class dataset _added_\\\n * all inactive-class dataset _removed_. When inactive, this process is reversed.\n *\n * Actions:\n * - toggle\n * - forceActive\n * - forceInactive\n *\n * Targets:\n * - toggle : element to toggle the classes of\n *\n * Values:\n * - active (Boolean)\n *\n * Example:\n * \n */\nexport default class TogglerController extends Controller {\n declare activeValue: boolean\n static values = { active: Boolean }\n\n declare readonly toggleTargets: HTMLElement[]\n static targets = [\"toggle\"]\n\n activeValueChanged() {\n const activeMethod = this.activeValue ? \"add\" : \"remove\"\n const inactiveMethod = this.activeValue ? \"remove\" : \"add\"\n\n this.toggleTargets.forEach(target => {\n const {\n togglerActiveClass: activeClasses,\n togglerInactiveClass: inactiveClasses,\n } = target.dataset\n\n if (activeClasses)\n target.classList[activeMethod](...activeClasses.split(\" \"))\n\n if (inactiveClasses)\n target.classList[inactiveMethod](...inactiveClasses.split(\" \"))\n })\n }\n\n toggle = () => (this.activeValue = !this.activeValue)\n forceActive = () => (this.activeValue = true)\n forceInactive = () => (this.activeValue = false)\n}\n","import * as Turbo from \"@hotwired/turbo\"\nimport { Application } from \"@hotwired/stimulus\"\nimport { registerControllers } from \"stimulus-vite-helpers\"\n\nTurbo.start()\n\nconst application = Application.start()\napplication.debug = true\nwindow.application = application\n\nexport const controllers = import.meta.globEager('../controllers/**/*_controller.*')\nregisterControllers(application, controllers)\n\nfunction uploadPreviewComponent() {\n return {\n expanded: false,\n hasImage: false,\n dragging: false,\n updatePreview() {\n let file = this.$refs.input.files[0]\n let imageTag = this.$refs.image\n\n let reader = new FileReader()\n reader.onload = (e) => {\n imageTag.src = e.target.result\n }\n\n reader.readAsDataURL(file)\n\n this.hasImage = true\n },\n drop: {\n [\"@drop.stop.prevent\"](event) {\n this.$refs.input.files = event.dataTransfer.files\n this.updatePreview()\n },\n [\"@drag.stop.prevent\"]() {},\n [\"@dragstart.stop.prevent\"]() {},\n [\"@dragover.stop.prevent\"]() {\n this.dragging = true\n },\n [\"@dragenter.stop.prevent\"]() {\n this.dragging = true\n },\n [\"@dragleave.stop.prevent\"]() {\n this.dragging = false\n },\n [\"@dragend.stop.prevent\"]() {\n this.dragging = false\n },\n [\"@paste.window\"](event) {\n if (event.clipboardData.files.length == 0) return\n\n event.preventDefault()\n event.stopPropagation()\n\n this.$refs.input.files = event.clipboardData.files\n this.updatePreview()\n }\n }\n }\n}\n\nwindow.uploadPreviewComponent = uploadPreviewComponent\n"],"names":["Turbo.start"],"mappings":"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"}