import { Controller } from "@hotwired/stimulus" // Handles flashcard flip + keyboard + swipe for both filter and review pages. // Expected DOM: // data-controller="flashcard" // data-flashcard-target="card" (the 3D flippable element) // // Hidden forms in the same element: // id="form-right" — known / easy // id="form-left" — learning / forgot // id="form-skip" — skip (filter only) // id="form-q3" — hard (review only) // id="form-q4" — good (review only) export default class extends Controller { static targets = ["card"] connect() { this.flipped = false this.animating = false this.touchStartX = 0 this.touchStartY = 0 this._keydown = this.handleKeydown.bind(this) document.addEventListener("keydown", this._keydown) } disconnect() { document.removeEventListener("keydown", this._keydown) } // ── Keyboard ──────────────────────────────────────────────────────────────── handleKeydown(e) { if (this.animating) return switch (e.key) { case " ": e.preventDefault() this.flip() break case "ArrowDown": e.preventDefault() this.flip() break case "ArrowRight": e.preventDefault() this.slideAndSubmit("slide-right", "form-right") break case "ArrowLeft": e.preventDefault() this.slideAndSubmit("slide-left", "form-left") break case "s": case "S": case "ArrowUp": e.preventDefault() this.slideAndSubmit("slide-up", "form-skip") break case "1": e.preventDefault() this.slideAndSubmit("slide-left", "form-left") break case "2": e.preventDefault() this.slideAndSubmit("slide-up", "form-q3") break case "3": e.preventDefault() this.slideAndSubmit("slide-up", "form-q4") break case "4": e.preventDefault() this.slideAndSubmit("slide-right", "form-right") break } } // ── Touch / swipe ─────────────────────────────────────────────────────────── touchstart(e) { const t = e.changedTouches[0] this.touchStartX = t.clientX this.touchStartY = t.clientY } touchend(e) { if (this.animating) return const t = e.changedTouches[0] const dx = t.clientX - this.touchStartX const dy = t.clientY - this.touchStartY if (Math.abs(dx) < 20 && Math.abs(dy) < 20) return e.preventDefault() if (Math.abs(dx) >= Math.abs(dy) && Math.abs(dx) > 40) { dx > 0 ? this.slideAndSubmit("slide-right", "form-right") : this.slideAndSubmit("slide-left", "form-left") } } // ── Card flip ─────────────────────────────────────────────────────────────── flip(e) { if (e) e.stopPropagation() this.flipped = !this.flipped this.cardTarget.classList.toggle("is-flipped", this.flipped) } // ── Form submission ───────────────────────────────────────────────────────── slideAndSubmit(animClass, formId) { this.animating = true this.cardTarget.classList.add(animClass) setTimeout(() => { const form = this.element.querySelector(`#${formId}`) if (form) { form.requestSubmit() } else { this.animating = false this.cardTarget.classList.remove(animClass) } }, 220) } }