Skip to content

Commit 267678d

Browse files
FindHaofacebook-github-bot
authored andcommitted
Implement Sticky Kernel Selector in Overview (#43)
Summary: This pull request introduces a significant UI/UX enhancement to the `KernelOverview` page by implementing a sticky/floating header for the "Available Kernels" selector. This feature improves usability, especially on pages with many kernels, by ensuring the kernel selection controls are always accessible. **Key Features and Changes:** 1. **Sticky by Default:** The "Available Kernels" section now sticks to the top of the viewport by default as the user scrolls down the page. 2. **User-Controlled Toggle:** A toggle switch has been added next to the "Available Kernels" title, allowing users to enable or disable the sticky functionality as needed. 3. **Smart Collapsing:** * To conserve screen space, the sticky header automatically collapses to show only the first row. This preserves the context of adjacent kernels, which was a key part of the feedback during development. * When the user hovers over the collapsed bar, it smoothly expands to show all available kernels. 4. **Compact Sticky Design:** When in the sticky state, the entire header becomes more compact: * The "Available Kernels" title text is smaller. * The kernel selection buttons and the gaps between them are reduced in size. * Overall padding and margins are tightened. 5. **Robust and Responsive:** The component is fully responsive. It uses a `useLayoutEffect` hook to track the positions of the kernel buttons and correctly scrolls the active row into view. A `resize` event listener ensures this logic re-runs if the browser window is resized, so the correct row is always shown. **Implementation Details:** * A new reusable `ToggleSwitch.tsx` component was created. * The logic is self-contained within `KernelOverview.tsx`, using React hooks (`useState`, `useRef`, `useCallback`, `useLayoutEffect`) for state management and DOM interaction. * Styling is handled with conditional Tailwind CSS classes to ensure a smooth transition between states. *Default sticky and collapsed view:* <img width="1087" height="872" alt="sticky" src="https://github.com/user-attachments/assets/92385db8-1ea4-4a22-bc8c-e0786ae7e5a3" /> *Expanded view on hover:* <img width="1077" height="738" alt="hover" src="https://github.com/user-attachments/assets/62249419-a55b-43ba-b4a1-5d58f64305a6" /> Pull Request resolved: #43 Reviewed By: sfzhu93 Differential Revision: D78920093 Pulled By: FindHao fbshipit-source-id: 4dada09e9474f1a8012d5ae878969efbffc3003e
1 parent b1f70ba commit 267678d

File tree

2 files changed

+137
-7
lines changed

2 files changed

+137
-7
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React from "react";
2+
3+
/**
4+
* Props for the ToggleSwitch component.
5+
*/
6+
interface ToggleSwitchProps {
7+
/** Whether the switch is currently checked (on). */
8+
isChecked: boolean;
9+
/** Callback function that is called when the switch state changes. */
10+
onChange: (isChecked: boolean) => void;
11+
/** Optional label to display next to the switch. */
12+
label?: string;
13+
}
14+
15+
/**
16+
* A reusable toggle switch component with a label.
17+
*/
18+
const ToggleSwitch: React.FC<ToggleSwitchProps> = ({
19+
isChecked,
20+
onChange,
21+
label,
22+
}) => {
23+
const handleToggle = () => {
24+
onChange(!isChecked);
25+
};
26+
27+
return (
28+
<div className="flex items-center">
29+
{label && <span className="mr-2 text-sm font-medium">{label}</span>}
30+
<label className="relative inline-flex items-center cursor-pointer">
31+
<input
32+
type="checkbox"
33+
checked={isChecked}
34+
onChange={handleToggle}
35+
className="sr-only peer"
36+
/>
37+
<div
38+
className="
39+
w-11 h-6 bg-gray-200 rounded-full
40+
peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-blue-300
41+
peer-checked:bg-blue-600
42+
after:content-[''] after:absolute after:top-[2px] after:left-[2px]
43+
after:bg-white after:border-gray-300 after:border after:rounded-full
44+
after:h-5 after:w-5 after:transition-all
45+
peer-checked:after:translate-x-full peer-checked:after:border-white
46+
"
47+
></div>
48+
</label>
49+
</div>
50+
);
51+
};
52+
53+
export default ToggleSwitch;

website/src/pages/KernelOverview.tsx

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1-
import React from "react";
1+
import React, { useState, useRef, useLayoutEffect, useCallback } from "react";
22
import ArgumentViewer from "../components/ArgumentViewer";
33
import DiffViewer from "../components/DiffViewer";
44
import { ProcessedKernel } from "../utils/dataLoader";
5+
import ToggleSwitch from "../components/ToggleSwitch";
56

67
interface KernelOverviewProps {
8+
/** A list of all processed kernels available for viewing. */
79
kernels: ProcessedKernel[];
10+
/** The index of the currently selected kernel. */
811
selectedKernel: number;
12+
/** Callback function to handle kernel selection. */
913
onSelectKernel: (index: number) => void;
14+
/** Callback function to handle viewing an IR file. */
1015
onViewIR: (irType: string) => void;
1116
}
1217

@@ -74,12 +79,49 @@ const getSourceFilePath = (entry: any): string => {
7479
return "Invalid filename format";
7580
};
7681

82+
/**
83+
* The main component for displaying an overview of Triton kernels.
84+
* It includes a kernel selector, metadata display, launch analysis, and IR file links.
85+
*/
7786
const KernelOverview: React.FC<KernelOverviewProps> = ({
7887
kernels,
7988
selectedKernel,
8089
onSelectKernel,
8190
onViewIR,
8291
}) => {
92+
// State for controlling the sticky and collapsed behavior of the kernel selector
93+
const [isSticky, setIsSticky] = useState(true);
94+
const [isCollapsed, setIsCollapsed] = useState(true);
95+
const buttonsContainerRef = useRef<HTMLDivElement>(null);
96+
97+
/**
98+
* Adjusts the scroll position of the kernel buttons container to ensure
99+
* the selected kernel's row is visible when the header is sticky and collapsed.
100+
*/
101+
const adjustScroll = useCallback(() => {
102+
if (isSticky && isCollapsed && buttonsContainerRef.current) {
103+
const container = buttonsContainerRef.current;
104+
const selectedButton = container.children[selectedKernel] as
105+
| HTMLElement
106+
| undefined;
107+
108+
if (selectedButton) {
109+
// Scroll the container to bring the selected button's row into view
110+
container.scrollTop = selectedButton.offsetTop;
111+
}
112+
}
113+
}, [isSticky, isCollapsed, selectedKernel]);
114+
115+
// Effect to adjust scroll on state changes and listen for window resizing
116+
useLayoutEffect(() => {
117+
adjustScroll();
118+
119+
window.addEventListener("resize", adjustScroll);
120+
return () => {
121+
window.removeEventListener("resize", adjustScroll);
122+
};
123+
}, [adjustScroll, kernels]);
124+
83125
if (kernels.length === 0) {
84126
return (
85127
<div className="flex items-center justify-center h-screen">
@@ -97,15 +139,50 @@ const KernelOverview: React.FC<KernelOverviewProps> = ({
97139
</h1>
98140

99141
{/* Kernel Selection */}
100-
<div className="bg-white rounded-lg p-4 mb-4 shadow border border-gray-200">
101-
<h2 className="text-xl font-semibold mb-4 text-gray-800">
102-
Available Kernels
103-
</h2>
104-
<div className="flex flex-wrap gap-2">
142+
<div
143+
className={`bg-white rounded-lg shadow border border-gray-200 transition-all duration-300 mb-4 ${
144+
isSticky ? "sticky top-4 z-10 p-2" : "p-4"
145+
}`}
146+
onMouseEnter={() => isSticky && setIsCollapsed(false)}
147+
onMouseLeave={() => isSticky && setIsCollapsed(true)}
148+
>
149+
<div className={`flex items-center gap-4 ${isSticky ? "mb-2" : "mb-4"}`}>
150+
<h2
151+
className={`${
152+
isSticky ? "text-lg" : "text-xl"
153+
} font-semibold text-gray-800`}
154+
>
155+
Available Kernels
156+
</h2>
157+
<div className="flex items-center gap-2">
158+
<span
159+
className={`${
160+
isSticky ? "text-xs" : "text-sm"
161+
} text-gray-600`}
162+
>
163+
Sticky Header
164+
</span>
165+
<ToggleSwitch isChecked={isSticky} onChange={setIsSticky} />
166+
</div>
167+
</div>
168+
<div
169+
ref={buttonsContainerRef}
170+
className={`flex flex-wrap transition-all duration-300 ${
171+
isSticky ? "gap-1" : "gap-2"
172+
} ${
173+
isSticky && isCollapsed
174+
? "max-h-9 overflow-hidden"
175+
: "max-h-96"
176+
}`}
177+
>
105178
{kernels.map((k, index) => (
106179
<button
107180
key={index}
108-
className={`px-4 py-2 text-sm rounded-md transition-colors whitespace-nowrap ${
181+
className={`rounded-md transition-colors whitespace-nowrap ${
182+
isSticky
183+
? "px-3 py-1 text-xs"
184+
: "px-4 py-2 text-sm"
185+
} ${
109186
index === selectedKernel
110187
? "bg-blue-100 border border-blue-300 text-blue-800"
111188
: "bg-gray-50 border border-gray-200 hover:bg-blue-50 text-gray-800"

0 commit comments

Comments
 (0)