Skip to content
Merged
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
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@
"type": "string",
"default": "",
"description": "Your user ID for 'Assign to me'. Defaults to $USER if not set."
},
"beads.tooltipHoverDelay": {
"type": "number",
"default": 1000,
"minimum": 0,
"description": "Delay in milliseconds before showing bead description tooltip on hover. Set to 0 to disable tooltips."
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/backend/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export interface BeadsSummary {
// Settings that can be passed to webview
export interface WebviewSettings {
renderMarkdown: boolean;
tooltipHoverDelay: number; // 0 = disabled
}

// Messages sent from extension to webview
Expand Down
1 change: 1 addition & 0 deletions src/providers/BaseViewProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export abstract class BaseViewProvider implements vscode.WebviewViewProvider {
settings: {
renderMarkdown: config.get<boolean>("renderMarkdown", true),
userId,
tooltipHoverDelay: config.get<number>("tooltipHoverDelay", 1000),
},
});

Expand Down
3 changes: 2 additions & 1 deletion src/webview/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const initialState: AppState = {
summary: null,
loading: true,
error: null,
settings: { renderMarkdown: true, userId: "" },
settings: { renderMarkdown: true, userId: "", tooltipHoverDelay: 1000 },
};

export function App(): React.ReactElement {
Expand Down Expand Up @@ -146,6 +146,7 @@ export function App(): React.ReactElement {
selectedBeadId={state.selectedBeadId}
projects={state.projects}
activeProject={state.project}
tooltipHoverDelay={state.settings.tooltipHoverDelay}
onSelectProject={(projectId) =>
vscode.postMessage({ type: "selectProject", projectId })
}
Expand Down
1 change: 1 addition & 0 deletions src/webview/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export interface BeadsSummary {
export interface WebviewSettings {
renderMarkdown: boolean;
userId: string;
tooltipHoverDelay: number; // 0 = disabled
}

// Messages from extension to webview
Expand Down
23 changes: 17 additions & 6 deletions src/webview/views/IssuesView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ interface IssuesViewProps {
selectedBeadId: string | null;
projects: BeadsProject[];
activeProject: BeadsProject | null;
tooltipHoverDelay: number; // 0 = disabled
onSelectProject: (projectId: string) => void;
onSelectBead: (beadId: string) => void;
onUpdateBead: (beadId: string, updates: Partial<Bead>) => void;
Expand Down Expand Up @@ -107,6 +108,7 @@ export function IssuesView({
selectedBeadId,
projects,
activeProject,
tooltipHoverDelay,
onSelectProject,
onSelectBead,
onUpdateBead: _onUpdateBead,
Expand Down Expand Up @@ -165,11 +167,15 @@ export function IssuesView({
}, [hoveredRowId, beads]);

const handleRowMouseEnter = useCallback((e: React.MouseEvent<HTMLTableRowElement>, beadId: string) => {
// Skip if tooltips are disabled
if (tooltipHoverDelay === 0) return;

if (tooltipTimeoutRef.current) {
clearTimeout(tooltipTimeoutRef.current);
}
const rect = e.currentTarget.getBoundingClientRect();
const tooltipWidth = 300;
const tooltipMaxHeight = 200;
const padding = 8;

// Position below the row, left-aligned with some offset
Expand All @@ -181,19 +187,24 @@ export function IssuesView({
left = window.innerWidth - tooltipWidth - padding;
}

// If tooltip would go below viewport, show above instead
if (top + 150 > window.innerHeight) {
top = rect.top - 150 - padding;
// Check if tooltip would overflow below viewport
const spaceBelow = window.innerHeight - rect.bottom - padding;
const spaceAbove = rect.top - padding;

if (spaceBelow < tooltipMaxHeight && spaceAbove > spaceBelow) {
// Position above the row when there's more space above
top = rect.top - tooltipMaxHeight - padding;
// Clamp to viewport top
if (top < padding) {
top = rect.bottom + padding;
top = padding;
}
}

tooltipTimeoutRef.current = setTimeout(() => {
setHoveredRowId(beadId);
setTooltipPosition({ top, left });
}, 400);
}, []);
}, tooltipHoverDelay);
}, [tooltipHoverDelay]);

const handleRowMouseLeave = useCallback(() => {
if (tooltipTimeoutRef.current) {
Expand Down