Browse Source

fix(configure-ams-slot): expand long filament profile names inline on hover (issue #1237)

  Long preset names like "SUNLU PETG GLOW IN THE DARK GEN2 @Bambu Lab
  H2C 0.4 nozzle" were visually clipped in the Configure AMS Slot
  modal's preset picker. With several near-identical entries differing
  only in nozzle size, users had to open browser dev tools to tell
  them apart.

  A `title={preset.name}` alone was too slow visually — browsers wait
  500-1000ms before rendering native tooltips. The row now un-truncates
  inline on hover via group-hover:whitespace-normal + break-all, so the
  full name appears the moment the cursor enters the row. `truncate`
  stays as the default to keep the list compact when scanning.

  The native `title={preset.name}` is also kept as a belt-and-braces
  fallback for assistive tech and touch devices where :hover doesn't
  fire. Both desktop and mobile layouts updated.

  Test: new ConfigureAmsSlotModal.test.tsx regression that pins the
  truncate / group-hover:whitespace-normal / group-hover:break-all
  classes on the span, the title attribute, and the `group` class on
  the parent button — so a future refactor that drops any of those
  fails CI.
maziggy 2 weeks ago
parent
commit
20fa8fbfdc

File diff suppressed because it is too large
+ 0 - 0
CHANGELOG.md


+ 17 - 0
frontend/src/__tests__/components/ConfigureAmsSlotModal.test.tsx

@@ -338,6 +338,23 @@ describe('ConfigureAmsSlotModal', () => {
     });
   });
 
+  it('preset row expands inline on hover so the full name is readable (#1237)', async () => {
+    // Long preset names (e.g. "SUNLU PETG GLOW IN THE DARK GEN2 @Bambu Lab H2C 0.4 nozzle")
+    // get visually truncated; the row un-truncates on hover via group-hover so the
+    // nozzle suffix is readable without waiting on the browser's title-tooltip delay,
+    // and the title attribute remains as a fallback for assistive tech / touch.
+    render(<ConfigureAmsSlotModal {...defaultProps} />);
+    await waitFor(() => {
+      const fullName = 'Bambu PLA Basic @BBL X1C';
+      const span = screen.getByText(fullName);
+      expect(span).toHaveAttribute('title', fullName);
+      expect(span).toHaveClass('truncate');
+      expect(span).toHaveClass('group-hover:whitespace-normal');
+      expect(span).toHaveClass('group-hover:break-all');
+      expect(span.closest('button')).toHaveClass('group');
+    });
+  });
+
   it('pre-selects saved preset when opening configured slot', async () => {
     const slotInfo = {
       ...defaultProps.slotInfo,

+ 4 - 4
frontend/src/components/ConfigureAmsSlotModal.tsx

@@ -928,14 +928,14 @@ export function ConfigureAmsSlotModal({
                         key={preset.id}
                         data-preset-id={preset.id}
                         onClick={() => setSelectedPresetId(preset.id)}
-                        className={`w-full p-2 rounded-lg border text-left transition-colors ${
+                        className={`group w-full p-2 rounded-lg border text-left transition-colors ${
                           selectedPresetId === preset.id
                             ? 'bg-bambu-green/20 border-bambu-green'
                             : 'bg-bambu-dark border-bambu-dark-tertiary hover:border-bambu-gray'
                         }`}
                       >
                         <div className="flex items-center justify-between">
-                          <span className="text-white text-sm truncate">{preset.name}</span>
+                          <span className="text-white text-sm truncate group-hover:whitespace-normal group-hover:break-all" title={preset.name}>{preset.name}</span>
                           <div className="flex items-center gap-1 flex-shrink-0">
                             {preset.source === 'local' && (
                               <span className="text-xs px-1.5 py-0.5 rounded bg-green-500/20 text-green-400">
@@ -1163,14 +1163,14 @@ export function ConfigureAmsSlotModal({
                           key={preset.id}
                           data-preset-id={preset.id}
                           onClick={() => setSelectedPresetId(preset.id)}
-                          className={`w-full p-2 rounded-lg border text-left transition-colors ${
+                          className={`group w-full p-2 rounded-lg border text-left transition-colors ${
                             selectedPresetId === preset.id
                               ? 'bg-bambu-green/20 border-bambu-green'
                               : 'bg-bambu-dark border-bambu-dark-tertiary hover:border-bambu-gray'
                           }`}
                         >
                           <div className="flex items-center justify-between">
-                            <span className="text-white text-sm truncate">{preset.name}</span>
+                            <span className="text-white text-sm truncate group-hover:whitespace-normal group-hover:break-all" title={preset.name}>{preset.name}</span>
                             <div className="flex items-center gap-1 flex-shrink-0">
                               {preset.source === 'local' && (
                                 <span className="text-xs px-1.5 py-0.5 rounded bg-green-500/20 text-green-400">

File diff suppressed because it is too large
+ 0 - 0
static/assets/index-C6s72Emh.css


File diff suppressed because it is too large
+ 0 - 0
static/assets/index-DAgURsKu.css


File diff suppressed because it is too large
+ 0 - 0
static/assets/index-DVU9Hr5-.js


+ 2 - 2
static/index.html

@@ -26,8 +26,8 @@
 
     <!-- Splash screens for iOS -->
     <link rel="apple-touch-startup-image" href="./img/android-chrome-512x512.png" />
-    <script type="module" crossorigin src="./assets/index-CTp9rI34.js"></script>
-    <link rel="stylesheet" crossorigin href="./assets/index-DAgURsKu.css">
+    <script type="module" crossorigin src="./assets/index-DVU9Hr5-.js"></script>
+    <link rel="stylesheet" crossorigin href="./assets/index-C6s72Emh.css">
   </head>
   <body>
     <div id="root"></div>

Some files were not shown because too many files changed in this diff