Skip to content

Commit 6be69d4

Browse files
committed
fix: restore horizontal positioning logic
1 parent d949e56 commit 6be69d4

File tree

1 file changed

+54
-35
lines changed

1 file changed

+54
-35
lines changed

src/components/learning-path/LearningPathMap.tsx

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -649,41 +649,60 @@ export function LearningPathMap() {
649649
{/* Sprechblase mit Button (bei Hervorhebung) */}
650650
{activeBubble === i && (
651651
<g onClick={e => e.stopPropagation()}>
652-
<polygon
653-
points={`${cx},${cy + radius - 5} ${cx - 20},${cy + radius + 10.5} ${cx + 20},${cy + radius + 10.5}`}
654-
fill="rgba(255,255,255,0.9)"
655-
className="filter drop-shadow-md"
656-
/>
657-
<foreignObject
658-
x="10%"
659-
y={cy + radius + 10}
660-
width="80%"
661-
height={120}
662-
>
663-
<div className="bg-white bg-opacity-90 p-2 rounded-3xl shadow-md text-center text-sm h-full z-100 flex flex-col items-center justify-around">
664-
<p className="font-bold text-lg">{el.source.title}</p>
665-
<button
666-
className="bg-blue-500 text-white py-2 px-4 rounded-full hover:bg-blue-600 transition-colors"
667-
onClick={e => {
668-
e.stopPropagation()
669-
setActiveBubble(null)
670-
handleLearningPathStepClick(getClickParams())
671-
}}
672-
>
673-
{el.solvedPercentage > 0
674-
? el.source.type === 'challenge'
675-
? 'Challenge weiter'
676-
: el.source.type === 'video'
677-
? 'Video weiter'
678-
: 'Aufgabe weiter'
679-
: el.source.type === 'challenge'
680-
? 'Challenge starten'
681-
: el.source.type === 'video'
682-
? 'Video starten'
683-
: 'Aufgabe starten'}
684-
</button>
685-
</div>
686-
</foreignObject>
652+
{(() => {
653+
const svgWidth = 375 // Breite des viewBox
654+
const bubbleWidth = svgWidth * 0.8 // 80% der Breite (ca. 300px)
655+
const margin = 15 // 15px Abstand zu beiden Rändern
656+
const minX = margin // Minimaler x-Wert für die Bubble
657+
const maxX = svgWidth - bubbleWidth - margin // Maximaler x-Wert
658+
let offsetX = cx - bubbleWidth / 2 // Bubble zentriert zum Knoten
659+
660+
if (offsetX < minX) offsetX = minX
661+
if (offsetX > maxX) offsetX = maxX
662+
663+
return (
664+
<>
665+
{/* Pfeil (Polygon) */}
666+
<polygon
667+
points={`${cx},${cy + radius - 5} ${cx - 20},${cy + radius + 10.5} ${cx + 20},${cy + radius + 10.5}`}
668+
fill="rgba(255,255,255,0.9)"
669+
className="filter drop-shadow-md"
670+
/>
671+
<foreignObject
672+
x={offsetX}
673+
y={cy + radius + 10}
674+
width="80%"
675+
height={120}
676+
>
677+
<div className="bg-white bg-opacity-90 p-2 rounded-3xl shadow-md text-center text-sm h-full z-100 flex flex-col items-center justify-around">
678+
<p className="font-bold text-lg">
679+
{el.source.title}
680+
</p>
681+
<button
682+
className="bg-blue-500 text-white py-2 px-4 rounded-full hover:bg-blue-600 transition-colors"
683+
onClick={e => {
684+
e.stopPropagation()
685+
setActiveBubble(null)
686+
handleLearningPathStepClick(getClickParams())
687+
}}
688+
>
689+
{el.solvedPercentage > 0
690+
? el.source.type === 'challenge'
691+
? 'Challenge weiter'
692+
: el.source.type === 'video'
693+
? 'Video weiter'
694+
: 'Aufgabe weiter'
695+
: el.source.type === 'challenge'
696+
? 'Challenge starten'
697+
: el.source.type === 'video'
698+
? 'Video starten'
699+
: 'Aufgabe starten'}
700+
</button>
701+
</div>
702+
</foreignObject>{' '}
703+
</>
704+
)
705+
})()}
687706
</g>
688707
)}
689708

0 commit comments

Comments
 (0)