@@ -22,6 +22,8 @@ import {formatDateTimeDownToMS, getLastItem} from '@parca/utilities';
2222
2323import { hexifyAddress , truncateString , truncateStringReverse } from '../utils' ;
2424import { ExpandOnHover } from './ExpandOnHoverValue' ;
25+ import { gpuFrameInfo , type GpuFrameInfo } from './gpuFrameDescriptions' ;
26+ import { openInNewTab } from './openInNewTab' ;
2527import { useGraphTooltip } from './useGraphTooltip' ;
2628import { useGraphTooltipMetaInfo } from './useGraphTooltipMetaInfo' ;
2729
@@ -34,6 +36,7 @@ interface GraphTooltipArrowContentProps {
3436 row : number | null ;
3537 isFixed : boolean ;
3638 compareAbsolute : boolean ;
39+ frozen ?: boolean ;
3740}
3841
3942const NoData = ( ) : React . JSX . Element => {
@@ -49,6 +52,7 @@ const GraphTooltipArrowContent = ({
4952 row,
5053 isFixed,
5154 compareAbsolute,
55+ frozen = false ,
5256} : GraphTooltipArrowContentProps ) : React . JSX . Element => {
5357 const graphTooltipData = useGraphTooltip ( {
5458 table,
@@ -74,10 +78,21 @@ const GraphTooltipArrowContent = ({
7478 row : rowNumber ,
7579 } = graphTooltipData ;
7680
81+ const info = gpuFrameInfo ( name ) ;
82+
83+ // Outer card gains a subtle ring when frozen, matching the design's
84+ // `.is-frozen` treatment.
85+ const cardClassName = [
86+ 'flex w-auto max-w-[600px] min-w-[300px] flex-col justify-start rounded-lg border bg-gray-50 p-3 shadow-lg dark:bg-gray-900' ,
87+ frozen
88+ ? 'border-indigo-400/60 ring-2 ring-indigo-400/20 dark:border-indigo-400/40'
89+ : 'border-gray-300 dark:border-gray-500' ,
90+ ] . join ( ' ' ) ;
91+
7792 return (
7893 < div className = { `flex text-sm ${ isFixed ? 'w-full' : '' } ` } >
7994 < div className = { `m-auto w-full ${ isFixed ? 'w-full' : '' } ` } >
80- < div className = "flex w-auto max-w-[600px] min-w-[300px] flex-col justify-start rounded-lg border border-gray-300 bg-gray-50 p-3 shadow-lg dark:border-gray-500 dark:bg-gray-900" >
95+ < div className = { cardClassName } >
8196 < div className = "flex flex-row" >
8297 < div className = "mx-2" >
8398 < div className = "flex min-h-10 items-start justify-between gap-4 break-all font-semibold mb-2" >
@@ -120,16 +135,82 @@ const GraphTooltipArrowContent = ({
120135 </ table >
121136 </ div >
122137 </ div >
123- < div className = "flex w-full items-center gap-1 text-xs text-gray-500" >
124- < Icon icon = "iconoir:mouse-button-right" />
125- < div > Right click to show context menu</ div >
126- </ div >
138+ { info !== undefined && < GpuDescriptionBlock info = { info } /> }
139+ < ShortcutFooter frozen = { frozen } />
127140 </ div >
128141 </ div >
129142 </ div >
130143 ) ;
131144} ;
132145
146+ const GpuDescriptionBlock = ( { info} : { info : GpuFrameInfo } ) : React . JSX . Element => {
147+ const chipPrefix = info . kind === 'stall' ? 'Stall reason' : 'SASS instruction' ;
148+
149+ return (
150+ < div className = "mx-2 mt-3 border-t border-gray-200 pt-3 dark:border-gray-700" >
151+ < div className = "mb-2 text-xs font-semibold text-gray-700 dark:text-gray-200" >
152+ { chipPrefix } · { info . entry . reasonLabel }
153+ </ div >
154+ < div className = "font-mono text-[10px] uppercase tracking-wider text-gray-500 dark:text-gray-400" >
155+ Description
156+ </ div >
157+ < p className = "mt-1 text-xs leading-relaxed text-gray-600 dark:text-gray-300" >
158+ { info . entry . description }
159+ </ p >
160+ < button
161+ type = "button"
162+ onClick = { e => {
163+ e . preventDefault ( ) ;
164+ e . stopPropagation ( ) ;
165+ openInNewTab ( info . sourceUrl ) ;
166+ } }
167+ title = { info . sourceLabel }
168+ className = "mt-2 inline-flex cursor-pointer items-center gap-1 self-start text-[11px] text-indigo-600 hover:underline dark:text-indigo-400"
169+ >
170+ Docs
171+ < Icon icon = "iconoir:open-new-window" className = "opacity-80" width = { 11 } height = { 11 } />
172+ </ button >
173+ </ div >
174+ ) ;
175+ } ;
176+
177+ const ShortcutFooter = ( { frozen} : { frozen : boolean } ) : React . JSX . Element => (
178+ < div className = "mx-2 mt-3 flex flex-wrap items-center gap-x-3 gap-y-1 border-t border-gray-200 pt-2 text-[11px] text-gray-500 dark:border-gray-700 dark:text-gray-400" >
179+ < span
180+ className = { `inline-flex items-center gap-1.5 ${
181+ frozen ? 'text-gray-600 dark:text-gray-300' : ''
182+ } `}
183+ >
184+ < kbd
185+ className = { [
186+ 'inline-flex min-w-[18px] justify-center rounded border border-b-2 px-1 font-mono text-[10px] leading-4' ,
187+ frozen
188+ ? 'border-gray-300 bg-gray-200 text-gray-600 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300'
189+ : 'border-gray-300 bg-white text-gray-600 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-300' ,
190+ ] . join ( ' ' ) }
191+ >
192+ ⇧
193+ </ kbd >
194+ { frozen ? (
195+ < span >
196+ < b className = "font-semibold" > Frozen</ b > · release to resume hover
197+ </ span >
198+ ) : (
199+ < span >
200+ Hold < b className = "font-semibold" > Shift</ b > to freeze · interact
201+ </ span >
202+ ) }
203+ </ span >
204+ < span className = "inline-block h-3 w-px bg-gray-200 dark:bg-gray-700" />
205+ < span className = "inline-flex items-center gap-1.5" >
206+ < Icon icon = "iconoir:mouse-button-right" width = { 12 } height = { 14 } />
207+ < span >
208+ < b className = "font-semibold" > Right-click</ b > for context menu
209+ </ span >
210+ </ span >
211+ </ div >
212+ ) ;
213+
133214const TooltipMetaInfo = ( { table, row} : { table : Table ; row : number } ) : React . JSX . Element => {
134215 const {
135216 labelPairs,
0 commit comments