From 9fd54067ce257e028b02f4784568ff3f2bbb32ca Mon Sep 17 00:00:00 2001 From: Thomas Hallock Date: Sun, 2 Nov 2025 12:23:08 -0600 Subject: [PATCH] feat(rithmomachia): auto-size tab labels with react-textfit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- apps/web/package.json | 1 + .../components/PlayingGuideModal.tsx | 18 ++++++++++++------ pnpm-lock.yaml | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index ad07cd90..c331cade 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -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", diff --git a/apps/web/src/arcade-games/rithmomachia/components/PlayingGuideModal.tsx b/apps/web/src/arcade-games/rithmomachia/components/PlayingGuideModal.tsx index 0cbc507a..681e32f5 100644 --- a/apps/web/src/arcade-games/rithmomachia/components/PlayingGuideModal.tsx +++ b/apps/web/src/arcade-games/rithmomachia/components/PlayingGuideModal.tsx @@ -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} > - {section.icon} + + {section.icon} + {!isVeryNarrow && ( - - {isNarrow ? section.label.split(' ')[0] : section.label} - + + {section.label} + )} ))} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 905d0919..da3c1703 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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