|
2 | 2 | // @ts-ignore
|
3 | 3 | const prevReadAt = _prevReadAt_;
|
4 | 4 | const highlightCommentEls: HTMLElement[] = [];
|
5 |
| - const highlightCommentMarkMap: Map<HTMLElement, HTMLElement> = new Map(); |
6 | 5 |
|
7 | 6 | exec();
|
8 | 7 |
|
|
144 | 143 | function addHighlightIndicator() {
|
145 | 144 | if (!highlightCommentEls.length) return;
|
146 | 145 |
|
147 |
| - // https://blog.jxck.io/entries/2016-06-25/intersection-observer.html#intersection-observer |
148 |
| - const observer = new IntersectionObserver((changes) => { |
149 |
| - for (let change of changes) { |
150 |
| - if (change.isIntersecting) { |
151 |
| - const mark = highlightCommentMarkMap.get(change.target as HTMLElement); |
152 |
| - if (mark) mark.classList.add('highlight-indicator-mark-done'); |
153 |
| - } |
154 |
| - } |
155 |
| - }, {threshold: [0], rootMargin: '-40px'}); |
156 |
| - |
157 |
| - // create indicator |
| 146 | + // create indicator wrap |
158 | 147 | const indicatorWrapEl = document.createElement('div');
|
159 | 148 | indicatorWrapEl.classList.add('highlight-indicator-wrap');
|
160 | 149 | document.body.appendChild(indicatorWrapEl);
|
161 | 150 |
|
| 151 | + // create indicator |
162 | 152 | const indicatorEl = document.createElement('div');
|
163 | 153 | indicatorEl.classList.add('highlight-indicator');
|
164 | 154 | indicatorWrapEl.appendChild(indicatorEl);
|
165 | 155 |
|
166 |
| - const rect = document.querySelector('.js-discussion').getBoundingClientRect(); |
167 |
| - const timelineHeight = rect.height; |
168 |
| - const timelineOffset = rect.top + window.pageYOffset; //.js-discussionのheightを使うために、commentの絶対位置をオフセットする必要がある |
| 156 | + // create current-pos |
| 157 | + const currentPosEl = document.createElement('div') ; |
| 158 | + currentPosEl.classList.add('highlight-indicator-scroll-current-pos'); |
| 159 | + currentPosEl.style.opacity = '0'; |
| 160 | + indicatorEl.appendChild(currentPosEl); |
| 161 | + |
| 162 | + // calc timeline height |
| 163 | + const lastCommentBottom = getComments().pop().getBoundingClientRect().bottom; |
| 164 | + const timelineRect = document.querySelector('.js-discussion').getBoundingClientRect(); |
| 165 | + const timelineHeight = timelineRect.height - (timelineRect.bottom - lastCommentBottom); |
| 166 | + const timelineOffset = timelineRect.top + window.pageYOffset; //.js-discussionのheightを使うために、commentの絶対位置をオフセットする必要がある |
169 | 167 |
|
170 | 168 | // タイムラインの高さが小さいときは、インジケータも小さくする
|
171 | 169 | const indicatorHeight = Math.min(timelineHeight / window.innerHeight, 1);
|
172 | 170 | indicatorEl.style.height = `${indicatorHeight * 100}%`;
|
173 | 171 |
|
| 172 | + // コメントが画面に表示されたときにmarkを非表示にする |
| 173 | + // https://blog.jxck.io/entries/2016-06-25/intersection-observer.html#intersection-observer |
| 174 | + const highlightCommentMarkMap: Map<HTMLElement, HTMLElement> = new Map(); |
| 175 | + const observer = new IntersectionObserver((changes) => { |
| 176 | + for (let change of changes) { |
| 177 | + if (change.isIntersecting) { |
| 178 | + const mark = highlightCommentMarkMap.get(change.target as HTMLElement); |
| 179 | + if (mark) mark.classList.add('highlight-indicator-mark-done'); |
| 180 | + } |
| 181 | + } |
| 182 | + }, {threshold: [0], rootMargin: '-40px'}); |
| 183 | + |
| 184 | + // create mark |
174 | 185 | for (const comment of highlightCommentEls) {
|
175 | 186 | // calc mark position
|
176 | 187 | const commentRect = comment.getBoundingClientRect();
|
|
184 | 195 | const height = absHeight / timelineHeight * 100;
|
185 | 196 |
|
186 | 197 | // create mark
|
187 |
| - const markOffset = (50 - y) / 50 * 10; // markの位置がindicatorの上下ぴったりに来ないように、「中央(50%)を原点として、そこからの距離で0~10のオフセット」をつける |
| 198 | + // const markOffset = (50 - y) / 50 * 10; // markの位置がindicatorの上下ぴったりに来ないように、「中央(50%)を原点として、そこからの距離で0~10のオフセット」をつける |
188 | 199 | const mark = document.createElement('div');
|
189 | 200 | mark.classList.add('highlight-indicator-mark');
|
190 |
| - mark.style.top = `calc(${y}% + ${markOffset}px)`; |
| 201 | + // mark.style.top = `calc(${y}% + ${markOffset}px)`; |
| 202 | + mark.style.top = `${y}%`; |
191 | 203 | mark.style.height = `${height}%`;
|
192 | 204 | indicatorEl.appendChild(mark);
|
193 | 205 |
|
|
202 | 214 | // recursiveMarkDone(mark, marks);
|
203 | 215 | });
|
204 | 216 | }
|
| 217 | + |
| 218 | + // scroll position |
| 219 | + if (timelineRect.bottom > window.innerHeight) { |
| 220 | + window.addEventListener('wheel', async () => { |
| 221 | + const top = Math.max(0, window.scrollY - timelineRect.top); |
| 222 | + const bottom = Math.min(timelineHeight, (window.scrollY + window.innerHeight) - timelineRect.top); |
| 223 | + const height = (bottom - top) / timelineHeight; |
| 224 | + // if (Math.ceil(100 * height) >= 100) return; |
| 225 | + |
| 226 | + currentPosEl.style.top = `${top/timelineHeight * 100}%`; |
| 227 | + currentPosEl.style.height = `${height * 100}%`; |
| 228 | + currentPosEl.style.opacity = null; |
| 229 | + currentPosEl.style.display = null; |
| 230 | + currentPosEl.style.transition = null; |
| 231 | + currentPosEl.ontransitionend = null; |
| 232 | + |
| 233 | + const t = Date.now().toString(); |
| 234 | + currentPosEl.dataset['time'] = t; |
| 235 | + await sleep(300); |
| 236 | + if (currentPosEl.dataset['time'] === t) { |
| 237 | + currentPosEl.style.opacity = '0'; |
| 238 | + currentPosEl.style.transition = 'opacity 0.2s'; |
| 239 | + currentPosEl.ontransitionend = () => currentPosEl.style.display = 'none'; |
| 240 | + } |
| 241 | + }); |
| 242 | + } |
205 | 243 | }
|
206 | 244 |
|
207 | 245 | // function recursiveMarkDone(doneMark: HTMLElement, marks: HTMLElement[]) {
|
|
0 commit comments