diff --git a/components/journeys/SankeyJourney.tsx b/components/journeys/SankeyJourney.tsx index d1958cd..b084b66 100644 --- a/components/journeys/SankeyJourney.tsx +++ b/components/journeys/SankeyJourney.tsx @@ -1,7 +1,7 @@ 'use client' import { useCallback, useEffect, useMemo, useState } from 'react' -import { ResponsiveSankey } from '@nivo/sankey' +import { Sankey } from '@nivo/sankey' import { TreeStructure, X } from '@phosphor-icons/react' import type { PathTransition } from '@/lib/api/journeys' @@ -36,7 +36,7 @@ const COLUMN_COLORS = [ '#EC4899', '#06B6D4', '#EF4444', '#84CC16', '#F97316', '#6366F1', ] -const MAX_NODES_PER_STEP = 15 +const MAX_NODES_PER_STEP = 25 // ─── Helpers ──────────────────────────────────────────────────────── @@ -257,9 +257,11 @@ export default function SankeyJourney({ } const labelColor = isDark ? '#a3a3a3' : '#525252' - const steps = data.nodes.map((n) => n.stepIndex) - const minStep = Math.min(...steps) - const maxStep = Math.max(...steps) + + // Calculate dimensions: give each step ~250px of horizontal space + const numSteps = new Set(data.nodes.map((n) => n.stepIndex)).size + const chartWidth = Math.max(800, numSteps * 250) + const chartHeight = 500 return (
@@ -283,73 +285,71 @@ export default function SankeyJourney({
)} -
- - data={data} - margin={{ top: 8, right: 140, bottom: 8, left: 140 }} - align="justify" - sort="descending" - colors={(node) => - COLUMN_COLORS[node.stepIndex % COLUMN_COLORS.length] - } - nodeThickness={12} - nodeSpacing={20} - nodeInnerPadding={0} - nodeBorderWidth={0} - nodeBorderRadius={3} - nodeOpacity={1} - nodeHoverOpacity={1} - nodeHoverOthersOpacity={0.3} - linkOpacity={0.2} - linkHoverOpacity={0.5} - linkHoverOthersOpacity={0.05} - linkContract={2} - enableLinkGradient - enableLabels - label={(node) => { - // Only show labels for first and last step columns - if (node.stepIndex === minStep || node.stepIndex === maxStep) { - return smartLabel(pathFromId(node.id)) +
+
+ + data={data} + width={chartWidth} + height={chartHeight} + margin={{ top: 8, right: 160, bottom: 8, left: 160 }} + align="justify" + sort="descending" + colors={(node) => + COLUMN_COLORS[node.stepIndex % COLUMN_COLORS.length] } - return '' - }} - labelPosition="outside" - labelPadding={8} - labelTextColor={labelColor} - isInteractive - onClick={handleClick} - nodeTooltip={({ node }) => ( -
-
- {pathFromId(node.id)} + nodeThickness={8} + nodeSpacing={8} + nodeInnerPadding={0} + nodeBorderWidth={0} + nodeBorderRadius={2} + nodeOpacity={1} + nodeHoverOpacity={1} + nodeHoverOthersOpacity={0.3} + linkOpacity={0.15} + linkHoverOpacity={0.5} + linkHoverOthersOpacity={0.03} + linkContract={1} + enableLinkGradient + enableLabels + label={(node) => smartLabel(pathFromId(node.id))} + labelPosition="outside" + labelPadding={6} + labelTextColor={labelColor} + isInteractive + onClick={handleClick} + nodeTooltip={({ node }) => ( +
+
+ {pathFromId(node.id)} +
+
+ Step {node.stepIndex + 1} ·{' '} + {node.value.toLocaleString()} sessions +
-
- Step {node.stepIndex + 1} ·{' '} - {node.value.toLocaleString()} sessions + )} + linkTooltip={({ link }) => ( +
+
+ {pathFromId(link.source.id)} →{' '} + {pathFromId(link.target.id)} +
+
+ {link.value.toLocaleString()} sessions +
-
- )} - linkTooltip={({ link }) => ( -
-
- {pathFromId(link.source.id)} →{' '} - {pathFromId(link.target.id)} -
-
- {link.value.toLocaleString()} sessions -
-
- )} - theme={{ - tooltip: { - container: { - background: 'transparent', - boxShadow: 'none', - padding: 0, + )} + theme={{ + tooltip: { + container: { + background: 'transparent', + boxShadow: 'none', + padding: 0, + }, }, - }, - }} - /> + }} + /> +
)