Преглед изворни кода

Scale the printer card's body text and icons with its size (#1848)

    Switching a card from M to XL made it wider, enlarged the printer name
    and the thumbnail, and left everything else where it was. The AMS slot
    labels, temperatures, filament names, status text and every small button
    stayed pinned between 8 and 11 pixels -- under the smallest size used
    anywhere else in the app -- so a full-width card carried the same tiny
    text as the compact one. Browser zoom does not answer this: it enlarges
    the whole page and so preserves the very disparity being reported.

    The card root now carries ten custom properties derived from cardSize,
    and the 200 fixed sizes in its subtree reference them: text-[10px]
    becomes text-[length:var(--pc-t10,10px)], w-3 h-3 becomes
    w-[var(--pc-i3,0.75rem)]. L draws the body 20% larger and XL 40%,
    icons included, so the controls grow with the text instead of staying
    fiddly to hit.

    Custom properties rather than an em-based root font-size. Setting
    font-size on the card would silently reshape any text that declares no
    size of its own, and would break for portalled content. Each converted
    class names its old fixed value as the fallback, so anything rendering
    outside a card root is untouched -- which is what leaves the portalled
    temperature popover exactly as it is. Its four sites stay fixed on
    purpose, as does the page chrome; the conversion was scoped from the
    function declarations rather than line numbers, and afterwards only
    those four intended sites still hold a literal px value.

    S and M stay at 1.0. S is the dense fleet view where density is the
    point and M is the default, so an existing install looks identical until
    the user reaches for a size that is already asking for more room -- the
    same control the request asked this to follow.

    Wiki notes the scaling in the card-size table and why it differs from
    browser zoom. Tests pin the variable values at every size, including
    that S and M still emit the pre-change sizes.
maziggy пре 3 недеља
родитељ
комит
751bf8d765

+ 133 - 0
frontend/src/__tests__/pages/PrintersPageCardScale.test.tsx

@@ -0,0 +1,133 @@
+/**
+ * Printer-card body scale (#1848, reporter @misterff1).
+ *
+ * S/M/L/XL already scaled the card's width, thumbnail and printer name, but
+ * every label in the body was pinned at 8-11px, so an XL card carried the same
+ * tiny text as an S one. The body now scales too, driven by custom properties
+ * on the card root.
+ *
+ * S and M stay at 1.0 on purpose: an existing install must look identical
+ * until the user reaches for a size that is already asking for more space.
+ */
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { screen, waitFor } from '@testing-library/react';
+import { render } from '../utils';
+import { PrintersPage } from '../../pages/PrintersPage';
+import { http, HttpResponse } from 'msw';
+import { server } from '../mocks/server';
+
+const mockPrinter = {
+  id: 1,
+  name: 'X1C',
+  ip_address: '192.168.1.100',
+  serial_number: '01P00A000000001',
+  access_code: '12345678',
+  model: 'X1C',
+  enabled: true,
+  nozzle_diameter: 0.4,
+  nozzle_type: 'stainless_steel',
+  location: 'Workshop',
+  auto_archive: true,
+  created_at: '2024-01-01T00:00:00Z',
+  updated_at: '2024-01-01T00:00:00Z',
+};
+
+const STATUS = {
+  connected: true,
+  state: 'IDLE',
+  progress: 0,
+  layer_num: 0,
+  total_layers: 0,
+  temperatures: { nozzle: 25, bed: 25, chamber: 25 },
+  remaining_time: 0,
+  filename: null,
+  wifi_signal: -29,
+  speed_level: 2,
+  ams: [],
+  vt_tray: [],
+};
+
+let store: Record<string, string>;
+
+/** Render at a given card size and hand back the card root's inline style. */
+async function cardStyleAt(cardSize: string) {
+  store['printerCardSize'] = cardSize;
+  render(<PrintersPage />);
+  const card = await waitFor(() => {
+    const el = document.getElementById('printer-card-1');
+    if (!el) throw new Error('card not rendered');
+    return el as HTMLElement;
+  });
+  return card.style;
+}
+
+describe('PrintersPage — printer card body scale (#1848)', () => {
+  beforeEach(() => {
+    store = {};
+    vi.mocked(localStorage.getItem).mockImplementation((key: string) => store[key] ?? null);
+    vi.mocked(localStorage.setItem).mockImplementation((key: string, value: string) => {
+      store[key] = String(value);
+    });
+    server.use(
+      http.get('/api/v1/printers/', () => HttpResponse.json([mockPrinter])),
+      http.get('/api/v1/printers/:id/status', () => HttpResponse.json(STATUS)),
+      http.get('/api/v1/queue/', () => HttpResponse.json([])),
+    );
+  });
+
+  afterEach(() => {
+    vi.mocked(localStorage.getItem).mockReset();
+    vi.mocked(localStorage.setItem).mockReset();
+  });
+
+  it('leaves M — the default — at the sizes shipped before this change', async () => {
+    const style = await cardStyleAt('2');
+
+    expect(style.getPropertyValue('--pc-t10')).toBe('10px');
+    expect(style.getPropertyValue('--pc-t8')).toBe('8px');
+    expect(style.getPropertyValue('--pc-i3')).toBe('12px');
+    expect(style.getPropertyValue('--pc-i4')).toBe('16px');
+  });
+
+  it('leaves S at the same sizes — the dense fleet view wants density', async () => {
+    const style = await cardStyleAt('1');
+
+    expect(style.getPropertyValue('--pc-t10')).toBe('10px');
+    expect(style.getPropertyValue('--pc-i3')).toBe('12px');
+  });
+
+  it('scales the body type and icons at L', async () => {
+    const style = await cardStyleAt('3');
+
+    expect(style.getPropertyValue('--pc-t10')).toBe('12px');
+    expect(style.getPropertyValue('--pc-t8')).toBe('9.6px');
+    expect(style.getPropertyValue('--pc-t11')).toBe('13.2px');
+    expect(style.getPropertyValue('--pc-i3')).toBe('14.4px');
+    expect(style.getPropertyValue('--pc-i4')).toBe('19.2px');
+  });
+
+  it('scales further at XL, where the card is full width', async () => {
+    const style = await cardStyleAt('4');
+
+    expect(style.getPropertyValue('--pc-t10')).toBe('14px');
+    expect(style.getPropertyValue('--pc-i4')).toBe('22.4px');
+    // 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']) {
+      expect(style.getPropertyValue(name)).not.toBe('');
+    }
+  });
+
+  it('drives real elements, not just the root variables', async () => {
+    await cardStyleAt('3');
+
+    // The printer name already scaled before this change and still does.
+    const heading = await screen.findByRole('heading', { name: 'X1C' });
+    expect(heading.className).toContain('text-xl');
+
+    // Body labels now reference the scaled property rather than a fixed px.
+    const scaled = document.querySelectorAll('#printer-card-1 [class*="--pc-t"]');
+    expect(scaled.length).toBeGreaterThan(0);
+  });
+});

Разлика између датотеке није приказан због своје велике величине
+ 175 - 134
frontend/src/pages/PrintersPage.tsx


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/assets/index-CJAv6Q5F.css


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
static/assets/index-Dl70tNWe.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 1
static/assets/index-GBTQ2eaA.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-COuw8Kkt.js"></script>
-    <link rel="stylesheet" crossorigin href="/assets/index-GBTQ2eaA.css">
+    <script type="module" crossorigin src="/assets/index-Dl70tNWe.js"></script>
+    <link rel="stylesheet" crossorigin href="/assets/index-CJAv6Q5F.css">
   </head>
   <body>
     <div id="root"></div>

Неке датотеке нису приказане због велике количине промена