Files
bambuddy/frontend
maziggy 50ec1872cb Restore the pointer cursor on interactive controls (#2791)
Hovering most of Bambuddy gave an arrow rather than a hand. Not everywhere,
    which is what made it read as sloppiness rather than a bug: the update pill was
    inert while the buttons beside it were fine, a bed or nozzle tile responded but
    the history-graph button in its corner did not, and dropdowns went either way
    with no pattern behind it.

    The pattern was there. Tailwind v3's Preflight set `button { cursor: pointer }`.
    v4 dropped it to match the browser default, which for a button is `default`.
    Bambuddy has been on v4 since the frontend was built, and `src/index.css` never
    had a base layer restoring it, so a button only looked clickable where someone
    had written `cursor-pointer` by hand. 15 of 934 had. 0 of 149 selects, and 19
    of 130 checkbox/radio inputs. The 233 ad-hoc `cursor-pointer` usages are why it
    looked arbitrary instead of uniformly broken.

    One `@layer base` rule now covers button, select, checkbox, radio, summary and
    [role=button]. base sits below utilities, so `cursor-not-allowed` and the
    `disabled:cursor-*` variants still win; the `:not(:disabled)` guard catches the
    disabled controls that carry no such utility. Verified against the built bundle
    rather than the source -- the rule lands inside @layer base, and
    `.cursor-not-allowed` is emitted after it.

    Click-outside backdrops are deliberately excluded. 90 of the 96 remaining
    onClick divs are `fixed inset-0` overlays; a full-screen sheet advertising
    itself as a button is worse than one that says nothing. Of the rest, 50 are
    stopPropagation wrappers and 3 are the temperature tiles, which already set the
    cursor through `statusControlClass` -- which is exactly why those tiles worked
    while the button nested inside them did not. That left two real ones: Card, now
    conditional on an onClick actually being passed, and the queue card, whose
    existing `sm:cursor-default` kept the desktop intent.

    Separately, from the same report. FilamentHoverCard draws the slot menu twice,
    and the two paths had drifted into opposite orders: Configure above Assign Spool
    on an empty slot, the reverse on a filled one, so the menu reshuffled itself
    depending on whether the slot held filament. Both now lead with the spool
    action. Tests assert the order on each path, so one can no longer move without
    the other -- checked by reinstating the old order and confirming the empty-slot
    test fails.

    Those buttons also used justify-center, which centred each label independently
    and left the icons in a ragged column; they are justify-start now. Their hover
    was a 10% opacity step that was very hard to see, now 20%. And the favourites
    star previews yellow on hover, suppressed when the user lacks archives:update.
2026-08-15 14:43:04 +02:00
..
…

React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

React Compiler

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see this documentation.

Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      // Other configs...

      // Remove tseslint.configs.recommended and replace with this
      tseslint.configs.recommendedTypeChecked,
      // Alternatively, use this for stricter rules
      tseslint.configs.strictTypeChecked,
      // Optionally, add this for stylistic rules
      tseslint.configs.stylisticTypeChecked,

      // Other configs...
    ],
    languageOptions: {
      parserOptions: {
        project: ['./tsconfig.node.json', './tsconfig.app.json'],
        tsconfigRootDir: import.meta.dirname,
      },
      // other options...
    },
  },
])

You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:

// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      // Other configs...
      // Enable lint rules for React
      reactX.configs['recommended-typescript'],
      // Enable lint rules for React DOM
      reactDom.configs.recommended,
    ],
    languageOptions: {
      parserOptions: {
        project: ['./tsconfig.node.json', './tsconfig.app.json'],
        tsconfigRootDir: import.meta.dirname,
      },
      // other options...
    },
  },
])