From 9d4032abf1ab33849a7cbc83d51411d73dc8a727 Mon Sep 17 00:00:00 2001 From: Hsieh Chin Fan Date: Mon, 30 Sep 2024 12:09:32 +0800 Subject: feat: improve actions in sub-menu * scroll to focus map/block * refactor methods in dumbyUtils * refactor MutationObserver for map --- src/MenuItem.mjs | 17 ++++++++++--- src/dumbyUtils.mjs | 71 ++++++++++++++++++++++++------------------------------ src/dumbymap.mjs | 6 ++--- 3 files changed, 47 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/MenuItem.mjs b/src/MenuItem.mjs index ac082b2..9830bf4 100644 --- a/src/MenuItem.mjs +++ b/src/MenuItem.mjs @@ -1,4 +1,5 @@ import { createGeoLink } from './dumbymap'; +import { scrollToBlock } from './dumbyUtils'; class Item { constructor({ text, innerHTML, onclick }) { @@ -55,7 +56,10 @@ export const pickMapItem = dumbymap => map => new Item({ text: map.id, - onclick: () => map.classList.add('focus'), + onclick: () => { + map.classList.add('focus'); + map.scrollIntoView({ behavior: 'smooth' }); + }, }).element, ), }).element; @@ -66,8 +70,15 @@ export const pickBlockItem = dumbymap => items: dumbymap.blocks.map( (block, index) => new Item({ - text: `Block ${index}`, - onclick: () => block.classList.add('focus'), + text: + block + .querySelector('p') + ?.textContent.substring(0, 20) + .concat(' ...') ?? `Block ${index}`, + onclick: () => { + block.classList.add('focus'); + scrollToBlock(block); + }, }).element, ), }).element; diff --git a/src/dumbyUtils.mjs b/src/dumbyUtils.mjs index 140d671..e7edee3 100644 --- a/src/dumbyUtils.mjs +++ b/src/dumbyUtils.mjs @@ -1,24 +1,41 @@ export function focusNextMap(reverse = false) { const renderedList = this.utils.renderedMaps(); + const index = renderedList.findIndex(e => e.classList.contains('focus')); + const nextIndex = + index === -1 ? 0 : (index + (reverse ? -1 : 1)) % renderedList.length; - const mapNum = renderedList.length; - if (mapNum === 0) return; - - // Get current focused map element - const currentFocus = this.container.querySelector('.mapclay.focus'); + const nextMap = renderedList.at(nextIndex); + nextMap.classList.add('focus'); +} - // Get next existing map element - const padding = reverse ? -1 : 1; - let nextIndex = currentFocus - ? renderedList.indexOf(currentFocus) + padding - : 0; - nextIndex = (nextIndex + mapNum) % mapNum; - const nextFocus = renderedList[nextIndex]; - nextFocus.classList.add('focus'); +export function focusNextBlock(reverse = false) { + const blocks = this.blocks.filter(b => + b.checkVisibility({ + contentVisibilityAuto: true, + opacityProperty: true, + visibilityProperty: true, + }), + ); + const index = blocks.findIndex(e => e.classList.contains('focus')); + const nextIndex = + index === -1 ? 0 : (index + (reverse ? -1 : 1)) % blocks.length; - return nextFocus; + const nextBlock = blocks.at(nextIndex); + blocks.forEach(b => b.classList.remove('focus')); + nextBlock?.classList?.add('focus'); + scrollToBlock(nextBlock); } +// Consider block is bigger then viewport height +export const scrollToBlock = block => { + const parentRect = block.parentElement.getBoundingClientRect(); + const scrollBlock = + block.getBoundingClientRect().height > parentRect.height * 0.8 + ? 'nearest' + : 'center'; + block.scrollIntoView({ behavior: 'smooth', block: scrollBlock }); +}; + export function focusDelay() { return window.getComputedStyle(this.showcase).display === 'none' ? 50 : 300; } @@ -36,32 +53,6 @@ export function switchToNextLayout(reverse = false) { this.container.setAttribute('data-layout', nextLayout.name); } -export function focusNextBlock(reverse = false) { - const blocks = this.blocks.filter(b => - b.checkVisibility({ - contentVisibilityAuto: true, - opacityProperty: true, - visibilityProperty: true, - }), - ); - const currentBlock = blocks.find(b => b.classList.contains('focus')); - const currentIndex = blocks.indexOf(currentBlock); - const padding = reverse ? -1 : 1; - const nextIndex = - currentIndex === -1 - ? 0 - : (currentIndex + padding + blocks.length) % blocks.length; - const nextBlock = blocks[nextIndex]; - blocks.forEach(b => b.classList.remove('focus')); - nextBlock?.classList?.add('focus'); - const scrollBlock = - nextBlock.getBoundingClientRect().height > - nextBlock.parentElement.getBoundingClientRect().height * 0.8 - ? 'nearest' - : 'center'; - nextBlock.scrollIntoView({ behavior: 'smooth', block: scrollBlock }); -} - export function removeBlockFocus() { this.blocks.forEach(b => b.classList.remove('focus')); } diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs index faa0621..7a54d73 100644 --- a/src/dumbymap.mjs +++ b/src/dumbymap.mjs @@ -270,9 +270,7 @@ export const generateMaps = (container, { delay, mapCallback }) => { new MutationObserver(mutations => { const mutation = mutations.at(-1); const target = mutation.target; - const focus = target - .getAttribute(mutation.attributeName) - .includes('focus'); + const focus = target.classList.contains('focus'); const shouldBeInShowcase = focus && showcase.checkVisibility({ @@ -284,7 +282,7 @@ export const generateMaps = (container, { delay, mapCallback }) => { if (focus) { dumbymap.utils .renderedMaps() - .filter(map => map !== target) + .filter(map => map.id !== target.id) .forEach(map => map.classList.remove('focus')); } -- cgit v1.2.3-70-g09d2