generated from boboko/starter
general products page and small rewrite of search and category controllers etc
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import { Controller } from '@hotwired/stimulus'
|
||||
|
||||
// Turbo doesn't scroll for <turbo-frame> navigations, so after the frame swaps
|
||||
// its contents (a sort, filter, or pagination link) this brings the top of the
|
||||
// frame back into view — otherwise clicking pagination at the bottom of the
|
||||
// list leaves you stranded down there. The frame's own scroll-margin-top keeps
|
||||
// it clear of the sticky header.
|
||||
//
|
||||
// `turbo:frame-render` fires only on a content swap, not on the initial page
|
||||
// render, and the frame element itself persists across swaps — so the listener
|
||||
// is bound once in connect().
|
||||
export default class extends Controller {
|
||||
connect() {
|
||||
this.element.addEventListener('turbo:frame-render', this.#toTop)
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.element.removeEventListener('turbo:frame-render', this.#toTop)
|
||||
}
|
||||
|
||||
#toTop = () => {
|
||||
this.element.scrollIntoView({ block: 'start', behavior: 'smooth' })
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import AutoSubmitController from './auto-submit-controller'
|
||||
import BackToTopController from './back-to-top-controller'
|
||||
import CarouselController from './carousel-controller'
|
||||
import DropdownController from './dropdown-controller'
|
||||
import FrameScrollController from './frame-scroll-controller'
|
||||
import NavSearchController from './nav-search-controller'
|
||||
import ProductFormController from './product-form-controller'
|
||||
import ProductGalleryController from './product-gallery-controller'
|
||||
import QuantityController from './quantity-controller'
|
||||
@@ -21,6 +23,8 @@ export function registerControllers(application) {
|
||||
application.register('back-to-top', BackToTopController)
|
||||
application.register('carousel', CarouselController)
|
||||
application.register('dropdown', DropdownController)
|
||||
application.register('frame-scroll', FrameScrollController)
|
||||
application.register('nav-search', NavSearchController)
|
||||
application.register('product-form', ProductFormController)
|
||||
application.register('product-gallery', ProductGalleryController)
|
||||
application.register('quantity', QuantityController)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Controller } from '@hotwired/stimulus'
|
||||
|
||||
// The search overlay is a [popover] that must sit exactly over the header. The
|
||||
// header has no fixed height below `lg`, so on open we copy its current height
|
||||
// onto --search-overlay-h and move focus into the field. Escape / click-away
|
||||
// close come from the Popover API; the fade is CSS (#search-overlay).
|
||||
export default class extends Controller {
|
||||
static targets = ['input']
|
||||
|
||||
connect() {
|
||||
this.element.addEventListener('toggle', this.#onToggle)
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.element.removeEventListener('toggle', this.#onToggle)
|
||||
}
|
||||
|
||||
#onToggle = (event) => {
|
||||
if (event.newState !== 'open') return
|
||||
|
||||
const header = this.element.closest('header')
|
||||
if (header) {
|
||||
this.element.style.setProperty('--search-overlay-h', `${header.offsetHeight}px`)
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => this.inputTarget.focus())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user