Skip to content

Commit e34b627

Browse files
committed
enhance(client): visualize scroll depth
Adds scroll depth visualization.
1 parent bf3f060 commit e34b627

File tree

3 files changed

+89
-2
lines changed

3 files changed

+89
-2
lines changed

client/src/app.tsx

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect } from "react";
1+
import React, { useEffect, useRef, useState } from "react";
22
import {
33
Navigate,
44
Routes,
@@ -43,9 +43,12 @@ const WritersHomepage = React.lazy(() => import("./writers-homepage"));
4343
const Sitemap = React.lazy(() => import("./sitemap"));
4444
const Playground = React.lazy(() => import("./playground"));
4545
const Observatory = React.lazy(() => import("./observatory"));
46+
const Debug = React.lazy(
47+
/* webpackChunkName: "debug" */ () => import("./ui/molecules/debug")
48+
);
4649

4750
function Layout({ pageType, children }) {
48-
const { pathname } = useLocation();
51+
const { pathname, hash } = useLocation();
4952
const [category, setCategory] = React.useState<string | null>(
5053
getCategoryByPathname(pathname)
5154
);
@@ -71,6 +74,11 @@ function Layout({ pageType, children }) {
7174
{children}
7275
</div>
7376
<Footer />
77+
{hash === "#debug" && (
78+
<React.Suspense>
79+
<Debug />
80+
</React.Suspense>
81+
)}
7482
</>
7583
);
7684
}
@@ -387,6 +395,7 @@ function useScrollDepthMeasurement(thresholds = [25, 50, 75]) {
387395
);
388396

389397
matchingThresholds.forEach((threshold) => {
398+
console.log({ threshold });
390399
gtag("event", "scroll", {
391400
percent_scrolled: String(threshold),
392401
});
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.debug {
2+
.scroll-depth {
3+
--color: #f00;
4+
5+
.depth {
6+
background-color: var(--color);
7+
height: 1px;
8+
left: 0;
9+
position: absolute;
10+
width: 100%;
11+
12+
&::after {
13+
background-color: var(--background-primary);
14+
border: 1px solid var(--color);
15+
content: attr(data-text);
16+
left: 50%;
17+
padding: 0 5px;
18+
position: absolute;
19+
transform: translateX(-50%) translateY(-50%);
20+
}
21+
}
22+
}
23+
}
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { useEffect, useRef, useState } from "react";
2+
3+
import "./index.scss";
4+
5+
export default function Debug() {
6+
return (
7+
<div className="debug">
8+
<DebugScrollDepth />
9+
</div>
10+
);
11+
}
12+
13+
function DebugScrollDepth() {
14+
const ref = useRef<HTMLDivElement>(null);
15+
const [scrollHeight, setScrollHeight] = useState<number>(0);
16+
17+
useEffect(() => {
18+
const root = ref.current;
19+
20+
if (!root || !scrollHeight) {
21+
return;
22+
}
23+
24+
const depths = [25, 50, 75, 90];
25+
depths.forEach((depth) => {
26+
const div = document.createElement("div");
27+
div.className = "depth";
28+
div.dataset.text = `${depth}%`;
29+
div.style.top = `${(depth / 100) * scrollHeight}px`;
30+
root.appendChild(div);
31+
});
32+
33+
return () =>
34+
Array.from(root.children).forEach((child) => root.removeChild(child));
35+
}, [ref, scrollHeight]);
36+
37+
useEffect(() => {
38+
const handler = () => {
39+
setScrollHeight(document.documentElement.scrollHeight);
40+
};
41+
42+
const observer = new MutationObserver(handler);
43+
44+
observer.observe(document.body, {
45+
childList: true, // Monitor for added/removed elements
46+
subtree: true, // Monitor all descendants of body
47+
attributes: true, // Monitor attribute changes (can affect size)
48+
characterData: true, // Monitor text content changes
49+
});
50+
51+
return () => observer.disconnect();
52+
}, []);
53+
54+
return <div ref={ref} className="scroll-depth" />;
55+
}

0 commit comments

Comments
 (0)