Migrate UI package from Blueprint to Mantine - #627
Draft
noahm wants to merge 8 commits into
Draft
Conversation
Migrates the entire UI from @blueprintjs/* packages to @mantine/core, @mantine/dates, and @mantine/notifications, with @tabler/icons-react replacing @blueprintjs/icons. Highlights: - MantineProvider drives light/dark mode via the existing theme store (forceColorScheme), preserving OS preference sync, the in-app toggle, and OBS browser-source detection - Toaster adapter wraps @mantine/notifications behind the existing toaster.show()/clear() API used across the app - New shared EmptyState and HeaderBar components replace NonIdealState and Navbar - Blueprint's Omnibar song search replaced with a Mantine modal search with keyboard navigation - Gauntlet score editor rebuilt on Mantine Table with inline-editable cells and per-column sort menus (drops @blueprintjs/table) - Release date filter now uses @mantine/dates DateInput - Removed unused round-label and sortable-columns modules https://claude.ai/code/session_01Duin5Bjnq1D6V3XzXx5qiW
Brings the Mantine migration up to date with partykit, re-expressing the UI that landed upstream in the meantime with Mantine components: - config-select: batch export dialog and "From JSON / From scratch" creation, using Modal + Checkbox (Button.Group stacks vertically so the labels fit the narrow config column) - player-list-input: new drag-to-reorder player list ported to TextInput/ActionIcon, keeping react-movable and the stable player ids - diagnostics-dialog: new connection diagnostics panel ported to Modal/Alert/Badge, with the pending-count badge kept beside its heading - header: connection diagnostics menu item (IconActivityHeartbeat) - cab-management: OBS sources menu restructured to the nested Players > Single Player layout with the new player/N routes - dashboard: delete button for OBS text sources - card-label / acton-menu / drawing-labels: follow the switch from player indexes to player ids - toaster: added dismiss() and the "import" icon that the new sync and config-import code calls Non-UI logic (state slices, party server, sync manager, diagnostics, models) is taken from partykit unchanged. https://claude.ai/code/session_01Duin5Bjnq1D6V3XzXx5qiW
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Pill is Mantine's component for a tag with a built-in remove button, so it replaces the Badge that had a CloseButton stuffed into its rightSection. - the white outline is now on the pill itself, so it follows the pill's own radius. Before, the outline's 0.5em radius disagreed with the badge's `sm` radius and the two sets of corners visibly didn't line up - the remove button gets hover and focus-visible styling via Pill's `remove` Styles API slot, so it reads as its own click target. A darkening overlay works over every label color without a rule per color - Pill already stops click/mousedown propagation on remove, so removing a label no longer relies on our own stopPropagation to avoid opening the card's action menu - Pill hides its remove button from the tab order and from assistive tech (a PillsInput drives it from the surrounding input). Here it's the only way to undo an action, so it's restored to the tab order and given an aria-label https://claude.ai/code/session_01Duin5Bjnq1D6V3XzXx5qiW
The toaster module was a Blueprint-shaped shim (intent, timeout,
icon-by-string-name, a hand-built action button) sitting on top of
@mantine/notifications, and it lost the old behaviour where an intent
coloured the entire toast — Mantine only tints the icon.
Replaced it with src/notify, which passes Mantine's own notification
props straight through (title, loading, autoClose, allowClose, icon,
priority, position) and adds one thing on top: `intent`, which both picks
the colour and fills the whole surface via the Notification Styles API
slots, restoring the old at-a-glance read. Notifications with no intent
keep Mantine's default neutral treatment.
Adopted along the way, rather than porting the old shapes:
- the update flow is now one notification that transitions in place with
notifications.update: a non-dismissable spinner while the update
installs, then green with the Apply action. It previously cleared all
toasts and opened a second one under a different key — and those two
keys disagreed ("UpdateManager" vs "UpdateManger"), so the clear was
doing the work the key should have
- timeout: 0 -> autoClose: false, and allowClose where dismissing early
would be wrong
- icon-name strings ("warning-sign", "import", …) -> real Tabler icons,
which drops the lookup table entirely
- config load failure now puts the error text in the notification body
under a title instead of only in the console
- toaster.dismiss -> notify.hide, toaster.clear -> notify.clean
share and config-persistence render icons now, so they become .tsx.
https://claude.ai/code/session_01Duin5Bjnq1D6V3XzXx5qiW
Blueprint set `body { font-size: 14px }`; Mantine sets it to 16px. Nothing
in this repo overrides either, so every percentage-based font-size in our
own stylesheets grew by 14%, and the card text that stacks several of them
grew most visibly.
Scaled those percentages by 14/16 so they compute to the sizes they had
before: song name 19.6px, name translation 10.5px, match labels 28px,
weight percentages 9.8px. They stay percentages rather than becoming rem
so a custom OBS stylesheet can still scale a whole card by setting one
font-size on it.
Rules in rem or pt are untouched — Blueprint never changed the `html`
font-size, so those already computed the same under both.
https://claude.ai/code/session_01Duin5Bjnq1D6V3XzXx5qiW
Brings in the user-supplied SMX edit charts feature, re-expressing its UI
with Mantine:
- smx-edit-import: the publish dialog ported to Modal/TextInput/Textarea/
Alert, keeping the Turnstile widget, debounced lookup and publish gating
- song-card variants/smx: edit author byline and the QR share popover;
Blueprint's Barcode became IconQrcode, which is what that popover
actually shows
- song-card: variant-supplied info actions now drive the footer dropdown,
showing either the action menu or an open action's content
- acton-menu: info action rows use closeMenuOnClick={false}, matching
Blueprint's shouldDismissPopover={false} so the dropdown can swap to the
action's content in place
- version-select: Select has no action-row concept, so the custom-data
group's "create" entry is an option carrying a sentinel value that
onChange intercepts to open the dialog instead of selecting
- config-page/config-select: route-driven config selection and the
game-name-in-label change carried onto the Mantine markup
- song-search: chart identity de-duplication for edit charts
Two things fixed rather than carried over:
- turnstile.tsx assigned a ref during render, which fails the repo's own
oxlint rule on partykit as well; moved into an effect so validate passes
- the new 300%/115% font sizes were written against Blueprint's 14px base,
so they were scaled by 14/16 like the rest of our styles
Note: song-search/index.tsx contains a literal NUL byte (a `.join()`
separator), which makes git treat the file as binary and refuse to merge
it — this merge applied that file's changes by hand. Writing it as "\0"
here keeps the file mergeable.
https://claude.ai/code/session_01Duin5Bjnq1D6V3XzXx5qiW
…-migration-sju0b6 # Conflicts: # src/song-search/index.tsx
Select has no concept of an action row, so "Import StepManiaX edits…" was a normal option carrying a sentinel value, sitting at the bottom of ~40 games: indistinguishable from a game, and only reachable by scrolling to the end. Combobox gives control of the dropdown's contents, which buys three things: - Combobox.Search filters the list. With 40 data sets and growing, typing "pump" to get three results beats scrolling. - Combobox.Footer pins the import action outside the scrolling option list, so it stays visible — including while the list is filtered — and reads as an action rather than another game. - Group labels get their folder icon back, which the Blueprint menu had and Select's plain group headings dropped. The action is still a Combobox.Option so it stays in the arrow-key flow, and is intercepted in onOptionSubmit, so the sentinel can never become a value. https://claude.ai/code/session_01Duin5Bjnq1D6V3XzXx5qiW
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Increasingly the slow pace of blueprint is holding this app back, and feels bad to use for ethical reasons as well. Time for something new!