Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions website/src/components/ScrollButton/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React, { useEffect, useState } from 'react';
import styles from './styles.module.css';

export default function ScrollButton() {
const [showButton, setShowButton] = useState(false);

useEffect(() => {
const handleScroll = () => {
if (typeof window !== 'undefined') {
setShowButton(window.scrollY > 150);
}
};
Comment on lines +3 to +12
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scroll event handler is called on every scroll event without throttling or debouncing. This can cause performance issues on lower-end devices or during fast scrolling. Consider using a throttle or debounce mechanism to limit the frequency of state updates.

Suggested change
export default function ScrollButton() {
const [showButton, setShowButton] = useState(false);
useEffect(() => {
const handleScroll = () => {
if (typeof window !== 'undefined') {
setShowButton(window.scrollY > 150);
}
};
import throttle from 'lodash.throttle';
export default function ScrollButton() {
const [showButton, setShowButton] = useState(false);
useEffect(() => {
const handleScroll = throttle(() => {
if (typeof window !== 'undefined') {
setShowButton(window.scrollY > 150);
}
}, 100);

Copilot uses AI. Check for mistakes.

if (typeof window !== 'undefined') {
window.addEventListener('scroll', handleScroll);
// Initial check
handleScroll();
return () => window.removeEventListener('scroll', handleScroll);
}
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup function is only returned when window is defined, but if window is undefined during SSR, the useEffect returns undefined. This is inconsistent with the React hooks pattern. The condition check should be moved inside the event listener registration, or the cleanup should always be returned (even if it's a no-op function).

Suggested change
}
}
// Return a no-op cleanup function when window is undefined (e.g., during SSR)
return () => {};

Copilot uses AI. Check for mistakes.
}, []);

const scrollUp = () => {
if (typeof window !== 'undefined') {
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
}
};

return (
<div className={styles.scrollButtonContainer}>
{showButton && (
<button
onClick={scrollUp}
className={styles.scrollButton}
aria-label="Scroll to top"
data-test="scroll-button"
>
<svg
className={styles.scrollIcon}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="m18 15-6-6-6 6"/>
</svg>
</button>
)}
</div>
);
}
45 changes: 45 additions & 0 deletions website/src/components/ScrollButton/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
.scrollButtonContainer {
position: fixed;
bottom: 2rem;
right: 2rem;
z-index: 1000;
}

.scrollButton {
width: 3rem;
height: 3rem;
border-radius: 0.5rem;
border: 1px solid #e5e7eb;
background-color: #ffffff;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}

.scrollButton:hover {
background-color: #f9fafb;
transform: translateY(-0.25rem);
}

.scrollIcon {
width: 1.5rem;
height: 1.5rem;
color: #374151;
}

/* Dark mode styles */
html[data-theme="dark"] .scrollButton {
background-color: #1f2937;
border-color: #4b5563;
}

html[data-theme="dark"] .scrollButton:hover {
background-color: #374151;
}

html[data-theme="dark"] .scrollIcon {
color: #d1d5db;
}
2 changes: 2 additions & 0 deletions website/src/pages/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import Layout from "@theme/Layout";
import HomepageHeader from "../components/HomepageHeader";
import HomepageContent from "../components/HomepageContent";
import ScrollButton from "../components/ScrollButton";

export default function Home() {
return (
<Layout title="Home" description="Landing page for schema project">
<HomepageHeader />
<HomepageContent />
<ScrollButton />
</Layout>
);
}