Просмотр исходного кода

Grow the H2C nozzle rack with the printer card size

The six rack chips were a hard-coded 28 pixels at every card size, while
the body type and icons around them scale by 20% at L and 40% at XL. Set
the card larger and the rack stayed put -- a shrunken strip beside
neighbours that had grown around it, with the diameter figures pressing
against the edges of chips that had not moved.

The chips now read their size from the same scale as everything else,
which needed one new rung: the icon tokens run in quarter-rem steps (i2
is 8px, i3 12, i4 16, i5 20), so 28px is i7. S and M are unchanged, as
they are for every other property that control scales.

The card is sized to its contents, so it simply takes the extra width
rather than being told a new one -- and at L and XL that row has the room
to give, so the temperature readings beside it do not go back to wrapping.

Two tests: one pins i7 to 33.6px at L and adds it to the sweep asserting
every token is set at XL, the other asserts the chip reads the token, so
a revert to a fixed class fails rather than silently regressing.
maziggy 3 недель назад
Родитель
Сommit
4d458a5202

+ 1 - 1
CHANGELOG.md

@@ -26,7 +26,7 @@ All notable changes to Bambuddy will be documented in this file.
 - **The MQTT debug log now records the commands sent to a printer, not only what it reports back** — **Printer → Debug → MQTT** captured one side of the conversation. Bambuddy listens on both of a printer's topics, but the one carrying commands returned before anything was written to the log, so a capture could show every status push the printer made and nothing it was ever told — including the commands Bambu Studio sends over the local network, which is the only place they can be observed at all. Those now appear alongside Bambuddy's own, grouped under the outgoing filter. It is what lets a question like "which value does Studio put in this field?" be answered from a user's capture instead of guessed at, and it is why #2774 could not be taken further. Commands Bambuddy sends appear twice, once as it publishes and once as the broker echoes it back, and the pair is itself evidence the command reached the broker. Logging is off until switched on, as before. Covered by backend tests.
 - **The L and XL printer cards now scale their text and icons, not just their width (#1848, reporter @misterff1)** — Switching a card from M to XL made it wider, enlarged the printer name and the thumbnail, and left everything else exactly as it was: the AMS slot labels, temperatures, filament names, status text and every small button stayed pinned between 8 and 11 pixels, well under the smallest size used anywhere else in Bambuddy. The result was a full-width card carrying the same tiny text as the compact one, which is precisely the opposite of what someone reaching for a bigger card is asking for. Browser zoom is not an answer to this, since it enlarges the entire page and so preserves the very disparity being complained about. The card body now scales along with the card: L draws it 20% larger and XL 40% larger, icons included, so the controls grow with the text rather than staying fiddly to hit. The AMS-HT card needed two adjustments of its own, since its temperature and humidity readings sit beside the slot rather than under it. Its single slot was the only thing on that row able to grow, so it swallowed every spare pixel and pushed the readings hard against the card's edge — it is now capped at roughly two ordinary slots, which keeps them clear at any card width. The card itself also gained a ceiling of one full AMS card's width, so a unit that wraps onto a line of its own no longer stretches that single slot across the whole card. S and M are deliberately untouched — S is the dense fleet view where density is the point, and M is the default, so an existing install looks identical until you reach for a size that is already asking for more room. Wiki updated. Covered by frontend tests.
 - **The "Slicer Bundles (removed)" card is gone from Settings** — Bundle import was withdrawn in 0.2.5, and the panel it lived in was kept behind as a static notice explaining where the feature went and what to use instead. That notice has done its job: it has been visible for several releases, it was shown to everyone running the slicer sidecar whether or not they had ever imported a bundle, and it occupied a card in **Settings → Workflow** that could not be acted on. The card and its translations are removed. Nothing about slicing changes — single-preset import, Bambu Cloud and Orca Cloud sync all work as before, and the slice-time lookup order is still Imported, then Orca Cloud, then Bambu Cloud, then the sidecar's standard presets. In the same pass **G-code Injection** moved to the foot of the right-hand column, which evens out two columns that the removal had left lopsided; the card itself is unchanged, and the settings search still jumps straight to it. Wiki updated.
-- **The H2C nozzle rack no longer crowds the temperatures beside it, and its slots are numbered** — The rack card sat in the same row as the nozzle, bed and chamber readings, but it grew at twice their rate from a 190-pixel floor, so on anything wider than a compact card it claimed several hundred pixels to draw a row of six 28-pixel chips and left the rest empty. The width came out of its neighbours, which are the cards that actually need it: on a dual-nozzle machine the combined nozzle reading is "220° / 220°" and it was wrapping onto two lines beside a mostly blank rack. The card is now sized to what it draws and gives the remainder back; it can still give way and shrink on a narrow card rather than overflowing. Each slot also carries its physical rack position underneath it, 1 to 6, so a nozzle can be named rather than counted along — the numbering is positional, so an empty slot keeps its number and "the nozzle in slot 4" means the same thing however many of the six are occupied. Covered by frontend tests.
+- **The H2C nozzle rack no longer crowds the temperatures beside it, and its slots are numbered** — The rack card sat in the same row as the nozzle, bed and chamber readings, but it grew at twice their rate from a 190-pixel floor, so on anything wider than a compact card it claimed several hundred pixels to draw a row of six 28-pixel chips and left the rest empty. The width came out of its neighbours, which are the cards that actually need it: on a dual-nozzle machine the combined nozzle reading is "220° / 220°" and it was wrapping onto two lines beside a mostly blank rack. The card is now sized to what it draws and gives the remainder back; it can still give way and shrink on a narrow card rather than overflowing. Each slot also carries its physical rack position underneath it, 1 to 6, so a nozzle can be named rather than counted along — the numbering is positional, so an empty slot keeps its number and "the nozzle in slot 4" means the same thing however many of the six are occupied. The chips now also follow the printer card size control, which grows the body type and icons by 20% at **L** and 40% at **XL**: they were a hard-coded 28 pixels at every size, so as soon as the card was set larger the rack became a shrunken strip beside neighbours that had grown around it, with the diameter figures crowding the edges of chips that had not. **S** and **M** are unchanged, as they are for everything else that control scales. Covered by frontend tests.
 - **Error and warning toasts now stay up twice as long** — Every pop-up notification disappeared after three seconds regardless of what it said. That is about right for "Settings saved", which confirms something you just did and is skimmed rather than read, but errors and warnings are a different kind of message: they carry a reason, often one relayed from the printer or the backend, and they run to a couple of lines. Three seconds was not long enough to finish reading one, and a missed error message is gone for good — there is no notification history to go back to. Errors and warnings now hold for six seconds. Success and informational toasts keep the three-second default, so the common case of clicking something and seeing it confirmed is unchanged, and the close button and the manual dismiss work exactly as before on all of them. The background print-dispatch toast is unaffected: it stays up while it has work in progress and clears itself shortly after the last job settles. Covered by frontend tests.
 
 ### Fixed

+ 23 - 0
frontend/src/__tests__/pages/PrintersPage.test.tsx

@@ -840,6 +840,29 @@ describe('PrintersPage', () => {
       expect(numbers).toEqual(['1', '2', '3', '4', '5', '6']);
     });
 
+    it('sizes the rack chips from the card scale rather than a fixed 28px', async () => {
+      // The chips were hard-coded while the type and icons around them grow
+      // with the card size, so at L and XL the rack read as a shrunken strip
+      // next to neighbours that had grown by up to 40%.
+      server.use(
+        http.get('/api/v1/printers/:id/status', () => {
+          return HttpResponse.json(h2cStatus);
+        })
+      );
+
+      render(<PrintersPage />);
+
+      await waitFor(() => {
+        expect(screen.getAllByText('Nozzle Rack').length).toBeGreaterThan(0);
+      });
+
+      const rackLabel = screen.getAllByText('Nozzle Rack')[0];
+      const slotRow = rackLabel.parentElement!.querySelectorAll('div.flex')[0];
+      const chip = slotRow.querySelector('span[data-rack-diameter]')!.parentElement!;
+      expect(chip.className).toContain('w-[var(--pc-i7,28px)]');
+      expect(chip.className).toContain('h-[var(--pc-i7,28px)]');
+    });
+
     it('hides nozzle rack when only L/R nozzles present (H2D)', async () => {
       const h2dStatus = {
         ...mockPrinterStatus,

+ 5 - 1
frontend/src/__tests__/pages/PrintersPageCardScale.test.tsx

@@ -185,6 +185,9 @@ describe('PrintersPage — printer card body scale (#1848)', () => {
     expect(style.getPropertyValue('--pc-t11')).toBe('13.2px');
     expect(style.getPropertyValue('--pc-i3')).toBe('14.4px');
     expect(style.getPropertyValue('--pc-i4')).toBe('19.2px');
+    // The H2C rack chips. They were a hard-coded 28px, so the rack read as a
+    // shrunken strip beside neighbours that had grown 20%.
+    expect(style.getPropertyValue('--pc-i7')).toBe('33.6px');
   });
 
   it('scales further at XL, where the card is full width', async () => {
@@ -195,7 +198,8 @@ describe('PrintersPage — printer card body scale (#1848)', () => {
     // Every property is set at every size, so a converted class can never
     // fall through to its fallback while sitting inside a card.
     for (const name of ['--pc-t8', '--pc-t9', '--pc-t10', '--pc-t11',
-      '--pc-i2', '--pc-i25', '--pc-i3', '--pc-i35', '--pc-i4', '--pc-i5']) {
+      '--pc-i2', '--pc-i25', '--pc-i3', '--pc-i35', '--pc-i4', '--pc-i5',
+      '--pc-i7']) {
       expect(style.getPropertyValue(name)).not.toBe('');
     }
   });

+ 10 - 7
frontend/src/pages/PrintersPage.tsx

@@ -556,10 +556,11 @@ function NozzleRackCard({ slots, filamentInfo }: { slots: import('../api/client'
 
   return (
     // Sized to its contents rather than growing: the six chips are a fixed
-    // 28px each, so any extra width is dead space taken from the temperature
-    // cards beside it — which are flex-1 with a 0 basis and wrap their values
-    // ("220° / 220°") as soon as they lose it. Shrink stays enabled so the
-    // card still gives way on a narrow printer card instead of overflowing.
+    // width at any one card size, so extra width would be dead space taken
+    // from the temperature cards beside it — which are flex-1 with a 0 basis
+    // and wrap their values ("220° / 220°") as soon as they lose it. Shrink
+    // stays enabled so the card still gives way on a narrow printer card
+    // instead of overflowing.
     <div className="text-center px-2.5 py-1.5 bg-bambu-dark rounded-lg flex-[0_1_auto] flex flex-col justify-center">
       <p className="text-[length:var(--pc-t9,9px)] text-bambu-gray mb-1">{t('printers.nozzleRack')}</p>
       <div className="flex gap-[3px] justify-center">
@@ -572,7 +573,7 @@ function NozzleRackCard({ slots, filamentInfo }: { slots: import('../api/client'
             <NozzleSlotHoverCard key={slot.id >= 0 ? slot.id : `empty-${i}`} slot={slot} index={i} filamentName={slot.filament_id ? filamentInfo?.[slot.filament_id]?.name : undefined}>
               <div className="flex flex-col items-center gap-0.5">
                 <div
-                  className={`w-7 h-7 rounded flex items-center justify-center cursor-default transition-colors border-b-2 ${
+                  className={`w-[var(--pc-i7,28px)] h-[var(--pc-i7,28px)] rounded flex items-center justify-center cursor-default transition-colors border-b-2 ${
                     isEmpty
                       ? 'bg-bambu-dark-tertiary/20 border-bambu-dark-tertiary/20'
                       : 'bg-bambu-dark-tertiary/40 border-bambu-dark-tertiary/40'
@@ -589,8 +590,9 @@ function NozzleRackCard({ slots, filamentInfo }: { slots: import('../api/client'
                 </div>
                 {/* Physical rack position, so "swap the nozzle in slot 4" can be
                     acted on without counting chips. Sits below the chip rather
-                    than inside it: the chip is 28px and already carries the
-                    diameter over a filament-coloured background. */}
+                    than inside it: the chip is barely wider than its own
+                    diameter text and already carries that over a
+                    filament-coloured background. */}
                 <span className="text-[length:var(--pc-t8,8px)] leading-none tabular-nums text-bambu-gray/70">
                   {i + 1}
                 </span>
@@ -1834,6 +1836,7 @@ function buildCardScaleStyle(cardSize: number): React.CSSProperties {
     '--pc-i35': px(14),
     '--pc-i4': px(16),
     '--pc-i5': px(20),
+    '--pc-i7': px(28),
   } as React.CSSProperties;
 }
 

Разница между файлами не показана из-за своего большого размера
+ 0 - 1
static/assets/index-B3n6Lnj1.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
static/assets/index-BKSFEuQA.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 0
static/assets/index-n0K-Bu3y.css


+ 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-CiO0qpbC.js"></script>
-    <link rel="stylesheet" crossorigin href="/assets/index-B3n6Lnj1.css">
+    <script type="module" crossorigin src="/assets/index-BKSFEuQA.js"></script>
+    <link rel="stylesheet" crossorigin href="/assets/index-n0K-Bu3y.css">
   </head>
   <body>
     <div id="root"></div>

Некоторые файлы не были показаны из-за большого количества измененных файлов