({
tabs,
selectedIndex,
availableWidth,
showAllProjects = false
}: Props)
| 52 | return truncateToWidth(tag, availableForTag); |
| 53 | } |
| 54 | export function TagTabs({ |
| 55 | tabs, |
| 56 | selectedIndex, |
| 57 | availableWidth, |
| 58 | showAllProjects = false |
| 59 | }: Props): React.ReactNode { |
| 60 | const resumeLabel = showAllProjects ? 'Resume (All Projects)' : 'Resume'; |
| 61 | const resumeLabelWidth = resumeLabel.length + 1; // +1 for gap |
| 62 | |
| 63 | // Calculate how much space we have for tabs (use worst-case hint width) |
| 64 | const rightHintWidth = Math.max(RIGHT_HINT_WIDTH_WITH_COUNT, RIGHT_HINT_WIDTH_NO_COUNT); |
| 65 | const maxTabsWidth = availableWidth - resumeLabelWidth - rightHintWidth - 2; // 2 for gaps |
| 66 | |
| 67 | // Clamp selectedIndex to valid range |
| 68 | const safeSelectedIndex = Math.max(0, Math.min(selectedIndex, tabs.length - 1)); |
| 69 | |
| 70 | // Calculate width of each tab, with truncation for very long tags |
| 71 | const maxSingleTabWidth = Math.max(20, Math.floor(maxTabsWidth / 2)); // At least show half the space for one tab |
| 72 | const tabWidths = tabs.map(tab => getTabWidth(tab, maxSingleTabWidth)); |
| 73 | |
| 74 | // Find a window of tabs that fits, centered around selectedIndex |
| 75 | let startIndex = 0; |
| 76 | let endIndex = tabs.length; |
| 77 | |
| 78 | // Calculate total width of all tabs |
| 79 | const totalTabsWidth = tabWidths.reduce((sum, w, i) => sum + w + (i < tabWidths.length - 1 ? 1 : 0), 0); // +1 for gaps between tabs |
| 80 | |
| 81 | if (totalTabsWidth > maxTabsWidth) { |
| 82 | // Need to show a subset - account for left arrow when not at start |
| 83 | const effectiveMaxWidth = maxTabsWidth - LEFT_ARROW_WIDTH; |
| 84 | |
| 85 | // Start with the selected tab |
| 86 | let windowWidth = tabWidths[safeSelectedIndex] ?? 0; |
| 87 | startIndex = safeSelectedIndex; |
| 88 | endIndex = safeSelectedIndex + 1; |
| 89 | |
| 90 | // Expand window to include more tabs |
| 91 | while (startIndex > 0 || endIndex < tabs.length) { |
| 92 | const canExpandLeft = startIndex > 0; |
| 93 | const canExpandRight = endIndex < tabs.length; |
| 94 | if (canExpandLeft) { |
| 95 | const leftWidth = (tabWidths[startIndex - 1] ?? 0) + 1; // +1 for gap |
| 96 | if (windowWidth + leftWidth <= effectiveMaxWidth) { |
| 97 | startIndex--; |
| 98 | windowWidth += leftWidth; |
| 99 | continue; |
| 100 | } |
| 101 | } |
| 102 | if (canExpandRight) { |
| 103 | const rightWidth = (tabWidths[endIndex] ?? 0) + 1; // +1 for gap |
| 104 | if (windowWidth + rightWidth <= effectiveMaxWidth) { |
| 105 | endIndex++; |
| 106 | windowWidth += rightWidth; |
| 107 | continue; |
| 108 | } |
| 109 | } |
| 110 | break; |
| 111 | } |
nothing calls this directly
no test coverage detected