Skip to content

Commit ff7cceb

Browse files
committed
feat: hide the SectionHighlighter component when scrolling the preview iframe
1 parent 069f519 commit ff7cceb

File tree

2 files changed

+60
-44
lines changed

2 files changed

+60
-44
lines changed

app/frontend/editor/components/section-highlighter/index.vue

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,31 @@
77
<div
88
class="w-full h-full relative mx-auto border-solid border-0 border-t-4 border-b-4"
99
:class="{
10-
'border-transparent': !hoveredSection,
11-
'border-editor-primary': hoveredSection,
10+
'border-transparent': !mustBeDisplayed,
11+
'border-editor-primary': mustBeDisplayed,
1212
}"
1313
>
1414
<transition
1515
name="slide-fade"
1616
mode="out-in"
17-
v-on:after-leave="afterAnimationDone"
1817
>
1918
<top-left-actions
2019
:hovered-section="hoveredSection"
21-
v-if="hoveredSection"
20+
v-if="mustBeDisplayed"
2221
/>
2322
</transition>
2423

2524
<transition name="reverse-slide-fade" mode="out-in">
2625
<top-right-actions
2726
:hoveredSection="hoveredSection"
28-
v-if="hoveredSection"
27+
v-if="mustBeDisplayed"
2928
/>
3029
</transition>
3130

3231
<transition name="slide-up-fade" mode="out-in">
3332
<bottom-actions
3433
:hovered-section="hoveredSection"
35-
v-if="hoveredSection"
34+
v-if="mustBeDisplayed"
3635
/>
3736
</transition>
3837
</div>
@@ -44,6 +43,7 @@ import TransformationMixin from '@/mixins/preview-transformation'
4443
import TopLeftActions from './top-left-actions.vue'
4544
import TopRightActions from './top-right-actions.vue'
4645
import BottomActions from './bottom-actions.vue'
46+
import { debounce } from '@/misc/utils'
4747
4848
export default {
4949
name: 'SectionHighlighter',
@@ -53,11 +53,11 @@ export default {
5353
hoveredSection: { type: Object },
5454
},
5555
data() {
56-
return { shadow: null, style: {} }
56+
return { style: {}, isScrolling: false, boundingRect: null }
5757
},
5858
mounted() {
59-
// NOTE: optimized version to update the highlighter when scrolling the iframe
6059
window.addEventListener('maglev:preview:scroll', this.onPreviewScroll)
60+
this.waitUntilScrollingDone = debounce(this.onEndPreviewScrolling.bind(this), 800)
6161
},
6262
beforeDestroy() {
6363
window.removeEventListener('maglev:preview:scroll', this.onPreviewScroll)
@@ -66,21 +66,28 @@ export default {
6666
minTop() {
6767
return this.hoveredSection?.sectionOffsetTop || 0
6868
},
69+
mustBeDisplayed() {
70+
return !!this.hoveredSection && !this.isScrolling
71+
}
6972
},
7073
methods: {
71-
afterAnimationDone() {
72-
this.shadow = null
74+
onPreviewScroll(event) {
75+
this.isScrolling = true
76+
this.boundingRect = event.detail.boundingRect
77+
this.waitUntilScrollingDone()
7378
},
74-
onPreviewScroll(event) {
75-
let self = this
76-
window.requestAnimationFrame(() => {
77-
const newStyle = this.performStyle(event.detail.boundingRect)
78-
Object.entries(newStyle).forEach(
79-
([key, value]) => (self.$el.style[key] = value),
80-
)
81-
})
79+
onEndPreviewScrolling() {
80+
this.isScrolling = false
81+
this.applyStyle(this.boundingRect)
8282
},
83-
performStyle(boundingRect) {
83+
applyStyle(boundingRect) {
84+
const self = this
85+
const newStyle = this.calculateStyle(boundingRect)
86+
Object.entries(newStyle).forEach(
87+
([key, value]) => (self.$el.style[key] = value),
88+
)
89+
},
90+
calculateStyle(boundingRect) {
8491
const isSticky = boundingRect.top < this.minTop
8592
const top = isSticky ? this.minTop : boundingRect.top
8693
const height = isSticky
@@ -102,17 +109,16 @@ export default {
102109
},
103110
},
104111
watch: {
105-
hoveredSection(value, oldValue) {
106-
if (!value) this.shadow = { ...oldValue }
107-
108-
if (!this.hoveredSection && !this.shadow) {
109-
this.style = {}
110-
return
111-
}
112+
hoveredSection: {
113+
handler(value) {
114+
if (!value) return
112115
113-
const { sectionRect } = value || this.shadow
114-
this.style = this.performStyle(sectionRect)
115-
},
116+
this.isScrolling = false
117+
this.boundingRect = value.sectionRect
118+
this.applyStyle(value.sectionRect)
119+
},
120+
immediate: true
121+
}
116122
},
117123
}
118124
</script>

app/frontend/live-preview-client/iframe-decorator.js

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,20 @@ export const start = (config) => {
5353

5454
// click on links
5555
disableLinks(previewDocument)
56+
57+
// Only works on Google Chrome
58+
selectHoveredSectionAtStartup(previewDocument, config.stickySectionIds)
59+
}
60+
61+
const selectHoveredSectionAtStartup = (previewDocument, stickySectionIds) => {
62+
setTimeout(() => {
63+
const section = previewDocument.querySelector('[data-maglev-section-id]:hover')
64+
65+
console.log('selectHoveredSectionAtStartup', section)
66+
67+
if (section)
68+
onSectionHovered(previewDocument, section, stickySectionIds)
69+
}, 200)
5670
}
5771

5872
const listen = (previewDocument, eventType, handler) => {
@@ -96,27 +110,23 @@ const listen = (previewDocument, eventType, handler) => {
96110
}
97111

98112
const listenScrolling = (previewDocument) => {
99-
let mouseX = 0
100-
let mouseY = 0
101-
102-
addEventListener(previewDocument, 'mousemove', (e) => {
103-
mouseX = e.clientX
104-
mouseY = e.clientY
105-
})
106-
107-
const debouncedScrollNotifier = debounce(() => {
108-
const el = previewDocument
109-
.elementFromPoint(mouseX, mouseY)
110-
?.closest('[data-maglev-section-id]')
111-
113+
// NOTE: to be used if too slow on old computers
114+
// const debouncedScrollNotifier = debounce(() => {
115+
// const el = previewDocument.querySelector('[data-maglev-section-id]:hover')
116+
// if (el) postMessage('scroll', { boundingRect: el.getBoundingClientRect() })
117+
// }, 10)
118+
119+
const scrollNotifier = () => {
120+
const el = previewDocument.querySelector('[data-maglev-section-id]:hover')
112121
if (el) postMessage('scroll', { boundingRect: el.getBoundingClientRect() })
113-
}, 10)
122+
}
114123

115-
addEventListener(previewDocument, 'scroll', debouncedScrollNotifier)
124+
addEventListener(previewDocument, 'scroll', scrollNotifier)
116125
}
117126

118127
const onSectionHovered = (previewDocument, el, stickySectionIds) => {
119128
const sectionId = el.dataset.maglevSectionId
129+
120130
if (hoveredSectionId !== sectionId) {
121131
postMessage('section:hover', {
122132
sectionId,

0 commit comments

Comments
 (0)