separate editor FAB and panel for cleaner animation
All checks were successful
deploy / deploy (push) Successful in 1m32s

Split the editor sheet into two distinct elements:
- .editor-fab: floating action button, always a pill in the corner
- .editor-panel: sliding panel that animates in/out independently

This enables proper CSS keyframe animations (slide-up/down on mobile,
slide-in/out on desktop) with a closing class for exit transitions.
Simplified the JS hook to only handle close behaviour.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-03-07 19:01:32 +00:00
parent 3f96769840
commit bd07c9c7d9
6 changed files with 230 additions and 249 deletions

View File

@@ -679,28 +679,25 @@ const DirtyGuard = {
}
}
// EditorSheet: simple open/collapse sheet for page editing
// Positioning is handled by CSS - JS just handles click-outside and Escape
// EditorSheet: handles click-outside and Escape for the editor panel
const EditorSheet = {
mounted() {
// Click outside to collapse (works in any mode for preview)
// Use mousedown instead of click to avoid race with LiveView re-renders
this._onDocMousedown = (e) => {
if (!this.el.contains(e.target) && this._getState() !== "collapsed") {
this._setState("collapsed")
}
if (this._getState() !== "open") return
const fab = document.querySelector(".editor-fab")
if (this.el.contains(e.target)) return
if (fab && fab.contains(e.target)) return
this._close()
}
document.addEventListener("mousedown", this._onDocMousedown)
// Escape key to collapse
this._onKeydown = (e) => {
if (e.key === "Escape" && this._getState() !== "collapsed") {
if (e.key === "Escape" && this._getState() === "open") {
e.preventDefault()
this._setState("collapsed")
this._close()
}
}
document.addEventListener("keydown", this._onKeydown)
},
destroyed() {
@@ -712,11 +709,22 @@ const EditorSheet = {
return this.el.dataset.state || "collapsed"
},
_setState(state) {
this.el.dataset.state = state
this.el.setAttribute("aria-expanded", state !== "collapsed")
this.pushEvent("editor_set_sheet_state", { state })
this._announce(state === "collapsed" ? "Editor collapsed" : "Editor expanded")
_close() {
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches
if (prefersReducedMotion) {
this.el.setAttribute("aria-hidden", "true")
this.pushEvent("editor_set_sheet_state", { state: "collapsed" })
this._announce("Editor collapsed")
return
}
this.el.classList.add("closing")
this.el.addEventListener("animationend", () => {
this.el.classList.remove("closing")
this.el.setAttribute("aria-hidden", "true")
this.pushEvent("editor_set_sheet_state", { state: "collapsed" })
this._announce("Editor collapsed")
}, { once: true })
},
_announce(message) {