Skip to content

Commit 7bbd005

Browse files
kubeclaude
andcommitted
Add hover tooltip and Logic Pro-style ruler to simulation timeline
- Hover tooltip: imperative DOM mounted in u.over (no React renders per mousemove). Run mode uses uPlot's nearest-series focus; stacked mode walks cumulative bands at the cursor's y to find the hit. Edge-clamps and flips above/below the cursor so it always fits in the chart area. - Top x-axis rendered as a Logic Pro-style ruler with a separator line. Playhead is a rounded-top "pin" with a triangular tip and white border, drawn in physical pixels with dpr-correct sizes. - Ruler scrubbing: clicks/drags on the axis area scrub the playhead via native pointer events with setPointerCapture. - Cursor unlocks (lock: false) so the dotted crosshair only shows on hover. - Add SubView.noPadding flag and move BottomPanel padding from the outer container into the header and the padded content variant, so noPadding subviews are truly full-bleed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f7eb5d7 commit 7bbd005

4 files changed

Lines changed: 348 additions & 30 deletions

File tree

libs/@hashintel/petrinaut/src/components/sub-view/horizontal/horizontal-tabs-container.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,21 @@ const tabButtonStyle = cva({
4141
},
4242
});
4343

44-
const contentStyle = css({
45-
fontSize: "xs",
46-
padding: "3",
47-
flex: "[1]",
48-
overflowY: "auto",
44+
const contentStyle = cva({
45+
base: {
46+
fontSize: "xs",
47+
flex: "[1]",
48+
overflowY: "auto",
49+
},
50+
variants: {
51+
padded: {
52+
// Includes the 4px that previously came from the outer panel container,
53+
// so padded subviews keep the same visual inset.
54+
true: { padding: "[16px]" },
55+
false: { padding: "0" },
56+
},
57+
},
58+
defaultVariants: { padded: true },
4959
});
5060

5161
interface TabButtonProps {
@@ -122,7 +132,7 @@ export const HorizontalTabsContainer: React.FC<
122132
{/* Content */}
123133
<div
124134
id={`tabpanel-${activeTabId}`}
125-
className={contentStyle}
135+
className={contentStyle({ padded: !activeSubView.noPadding })}
126136
role="tabpanel"
127137
aria-labelledby={`tab-${activeTabId}`}
128138
>
@@ -196,7 +206,7 @@ export const HorizontalTabsContent: React.FC<{
196206
return (
197207
<div
198208
id={tabpanelId}
199-
className={contentStyle}
209+
className={contentStyle({ padded: !activeSubView.noPadding })}
200210
role="tabpanel"
201211
aria-labelledby={tabId}
202212
>

libs/@hashintel/petrinaut/src/components/sub-view/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,11 @@ export interface SubView {
7272
* Only affects vertical layout. When set, the section can be resized by dragging its bottom edge.
7373
*/
7474
resizable?: SubViewResizeConfig;
75+
/**
76+
* When true, the horizontal tab content wrapper renders with no padding,
77+
* letting the subview occupy the full width/height of the panel area.
78+
* Useful for visualizations like charts that manage their own bounds.
79+
* Defaults to false.
80+
*/
81+
noPadding?: boolean;
7582
}

libs/@hashintel/petrinaut/src/views/Editor/panels/BottomPanel/panel.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ const panelStyle = cva({
5252
});
5353

5454
const panelContainerStyle = css({
55-
padding: "[4px]",
5655
display: "flex",
5756
flexDirection: "column",
5857
});
@@ -61,7 +60,7 @@ const headerStyle = css({
6160
display: "flex",
6261
alignItems: "center",
6362
justifyContent: "space-between",
64-
padding: "[2px]",
63+
padding: "[6px]",
6564
flexShrink: 0,
6665
});
6766

0 commit comments

Comments
 (0)