feat: implement smart tooltip positioning to avoid covering active beads

- Add collision detection to check for active beads in columns to the left
- Position tooltip to the left when safe, above heaven bead when collision detected
- Remove fixed left margin since tooltips can now position above when needed
- Ensure tooltip never covers beads with direction arrows or highlights

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-09-24 08:20:07 -05:00
parent 41dde87778
commit e104033371

View File

@@ -347,7 +347,7 @@ function TutorialPlayerContent({
return { before, highlighted, after }
}, [fullDecomposition, expectedSteps, currentMultiStep])
// Create overlay for tooltip positioned precisely at topmost bead using AbacusReact's overlay system
// Create overlay for tooltip positioned precisely at topmost bead using smart collision detection
const tooltipOverlay = useMemo(() => {
if (!currentStepSummary || !currentStepBeads?.length) {
return null
@@ -359,16 +359,37 @@ function TutorialPlayerContent({
return null
}
// Create an overlay that targets the specific bead and positions tooltip outside abacus
// Smart positioning logic: avoid covering active beads
const targetColumnIndex = 4 - topmostBead.placeValue // Convert placeValue to columnIndex (5 columns: 0-4)
// Check if there are any active beads (with arrows/highlights) in columns to the left
const hasActiveBeadsToLeft = currentStepBeads.some(bead => {
const beadColumnIndex = 4 - bead.placeValue
return beadColumnIndex < targetColumnIndex && bead.direction && bead.direction !== 'none'
})
// Determine tooltip position and target
const shouldPositionAbove = hasActiveBeadsToLeft
const tooltipSide = shouldPositionAbove ? 'top' : 'left'
const tooltipTarget = shouldPositionAbove ? {
// Target the heaven bead position for the column
type: 'bead' as const,
columnIndex: targetColumnIndex,
beadType: 'heaven' as const,
beadPosition: 0 // Heaven beads are always at position 0
} : {
// Target the actual bead
type: 'bead' as const,
columnIndex: targetColumnIndex,
beadType: topmostBead.beadType,
beadPosition: topmostBead.position
}
// Create an overlay that positions tooltip to avoid covering active beads
const overlay: AbacusOverlay = {
id: 'bead-tooltip',
type: 'tooltip',
target: {
type: 'bead',
columnIndex: 4 - topmostBead.placeValue, // Convert placeValue to columnIndex (5 columns: 0-4)
beadType: topmostBead.beadType,
beadPosition: topmostBead.position
},
target: tooltipTarget,
content: (
<Tooltip.Provider>
<Tooltip.Root open={true}>
@@ -377,7 +398,7 @@ function TutorialPlayerContent({
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content
side="left"
side={tooltipSide}
align="center"
sideOffset={20}
style={{
@@ -1116,8 +1137,7 @@ function TutorialPlayerContent({
borderColor: 'gray.200',
borderRadius: 'lg',
p: 6,
shadow: 'lg',
ml: '60px' // Left margin to accommodate tooltip
shadow: 'lg'
})}>
<AbacusReact
value={currentValue}