feat(rithmomachia): auto-size tab labels with react-textfit

Replace ellipsized tab labels with react-textfit library:
- Install react-textfit package
- Use Textfit component for tab text labels
- Auto-scales font size (8px-14px) using binary search to fit width
- No more ellipsis (...) on narrow tabs
- Full tab labels always visible and readable
- Icon stays fixed size, only text scales

Tab labels now automatically shrink to fit available space while
remaining fully readable.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-11-02 12:23:08 -06:00
parent d44e444efa
commit 9fd54067ce
3 changed files with 29 additions and 6 deletions

View File

@@ -73,6 +73,7 @@
"react-dom": "^18.2.0",
"react-resizable-layout": "^0.7.3",
"react-resizable-panels": "^3.0.6",
"react-textfit": "^1.1.1",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
"y-protocols": "^1.0.6",

View File

@@ -2,6 +2,7 @@
import { useEffect, useState, useRef } from 'react'
import { useTranslations } from 'next-intl'
import { Textfit } from 'react-textfit'
import { css } from '../../../../styled-system/css'
import { Z_INDEX } from '@/constants/zIndex'
import { useAbacusSettings } from '@/hooks/useAbacusSettings'
@@ -608,9 +609,7 @@ export function PlayingGuideModal({
justifyContent: 'center',
gap: isVeryNarrow ? '0' : isNarrow ? '4px' : '6px',
lineHeight: 1,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
onMouseEnter={(e) => {
if (activeSection !== section.id) {
@@ -624,11 +623,18 @@ export function PlayingGuideModal({
}}
title={section.label}
>
<span style={{ fontSize: isVeryNarrow ? '18px' : 'inherit' }}>{section.icon}</span>
<span style={{ fontSize: isVeryNarrow ? '18px' : 'inherit', flexShrink: 0 }}>
{section.icon}
</span>
{!isVeryNarrow && (
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>
{isNarrow ? section.label.split(' ')[0] : section.label}
</span>
<Textfit
mode="single"
min={8}
max={isNarrow ? 12 : 14}
style={{ width: '100%', height: '100%', display: 'flex', alignItems: 'center' }}
>
{section.label}
</Textfit>
)}
</button>
))}

16
pnpm-lock.yaml generated
View File

@@ -194,6 +194,9 @@ importers:
react-resizable-panels:
specifier: ^3.0.6
version: 3.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react-textfit:
specifier: ^1.1.1
version: 1.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
socket.io:
specifier: ^4.8.1
version: 4.8.1
@@ -7942,6 +7945,12 @@ packages:
'@types/react':
optional: true
react-textfit@1.1.1:
resolution: {integrity: sha512-UDSQRo5yBEGueLTE5SgNV9fSmr5CWJkE0E0R0YbcbCO69iuJGfcT6wspKhX2sIwdsDyT9qXOwMC80cnRolir7Q==}
peerDependencies:
react: ^15.0.0 || ^16.0.0
react-dom: ^15.0.0 || ^16.0.0
react@18.3.1:
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
engines: {node: '>=0.10.0'}
@@ -17896,6 +17905,13 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.26
react-textfit@1.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
process: 0.11.10
prop-types: 15.8.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react@18.3.1:
dependencies:
loose-envify: 1.4.0