## Summary
Fix right-side sidebar panels and left-side panels sharing the same
PrimeVue Splitter state key, causing them to incorrectly apply each
other's saved widths.
## Changes
- **What**: Make `sidebarStateKey` position-aware by including
`sidebarLocation` and offside panel visibility in the localStorage key
## Problem
When sidebar location is set to **right**, all panels (both the
right-side sidebar like Job History and left-side panels like Workflow
overview) share a single PrimeVue Splitter `state-key`
(`unified-sidebar`). PrimeVue persists panel widths to localStorage
using this key, so any resize on one side gets applied to the other.
### AS-IS (before fix)
The `sidebarStateKey` is computed without any awareness of panel
position:
```typescript
// Always returns 'unified-sidebar' (when unified width enabled)
// or the active tab id — regardless of sidebar location or offside panel state
const sidebarStateKey = computed(() => {
return unifiedWidth.value
? 'unified-sidebar'
: (activeSidebarTabId.value ?? 'default-sidebar')
})
```
This produces a **single localStorage key** for all layout
configurations. The result:
1. Set sidebar to **right**, open **Job History** → resize it smaller →
saved to `unified-sidebar`
2. Open **Workflow overview** (appears on the left as an offside panel)
→ loads the same `unified-sidebar` key → gets the Job History width
applied to a completely different panel position
3. Both panels open simultaneously share the same persisted width, even
though they are on opposite sides of the screen
This is exactly the behavior shown in the [issue
screenshots](https://github.com/Comfy-Org/ComfyUI_frontend/issues/9440):
pulling the Workflow overview smaller also changes Job History to that
same size, and vice versa.
### TO-BE (after fix)
The `sidebarStateKey` now includes `sidebarLocation` (`left`/`right`)
and whether the offside panel is visible:
```typescript
const sidebarTabKey = computed(() => {
return unifiedWidth.value
? 'unified-sidebar'
: (activeSidebarTabId.value ?? 'default-sidebar')
})
const sidebarStateKey = computed(() => {
const base = sidebarTabKey.value
const suffix = showOffsideSplitter.value ? '-with-offside' : ''
return `${base}-${sidebarLocation.value}${suffix}`
})
```
This produces **distinct localStorage keys** per layout configuration:
| Layout | Key |
|--------|-----|
| Sidebar left, no offside | `unified-sidebar-left` |
| Sidebar left, right panel open | `unified-sidebar-left-with-offside` |
| Sidebar right, no offside | `unified-sidebar-right` |
| Sidebar right, left panel open | `unified-sidebar-right-with-offside`
|
Each configuration now persists and restores its own panel sizes
independently, so resizing Job History on the right no longer affects
Workflow overview on the left.
## Review Focus
- The offside suffix (`-with-offside`) is necessary because the Splitter
transitions from a 2-panel layout (sidebar + center) to a 3-panel layout
(sidebar + center + offside) — these are fundamentally different panel
configurations and should not share persisted sizes.
Fixes#9440
## Screenshots (if applicable)
See issue for reproduction screenshots:
https://github.com/Comfy-Org/ComfyUI_frontend/issues/9440🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
## Summary
Fix the bottom-right graph canvas toolbar (zoom controls, fit-to-view,
minimap toggle) not being visible on mobile devices in normal graph
mode.
## Problem
PrimeVue applies `overflow: hidden` to all `.p-splitterpanel` elements
by default. The `GraphCanvasMenu` component is absolutely positioned
(`right-0 bottom-0`) inside the `graph-canvas-panel` SplitterPanel. On
mobile viewports, the panel's bounding box can be smaller than the full
canvas area, causing the toolbar to be clipped by the `overflow:
hidden`.
## Solution
Add `overflow-visible` to the `graph-canvas-panel` SplitterPanel class
to override PrimeVue's default `overflow: hidden`. This allows the
absolutely-positioned toolbar (and minimap) to remain visible regardless
of viewport size.
<img width="873" height="1056" alt="image"
src="https://github.com/user-attachments/assets/7239a5ce-8ce8-4e1d-a8ff-6d6d3c61f5da"
/>
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10168-fix-make-graph-canvas-toolbar-visible-on-mobile-3266d73d36508130b675e839cb748fd5)
by [Unito](https://www.unito.io)
## Summary
Enable `better-tailwindcss/enforce-consistent-class-order` lint rule and
auto-fix all 1027 violations across 263 files. Stacked on #9427.
## Changes
- **What**: Sort Tailwind classes into consistent order via `eslint
--fix`
- Enable `enforce-consistent-class-order` as `'error'` in eslint config
- Purely cosmetic reordering — no behavioral or visual changes
## Review Focus
Mechanical auto-fix PR — all changes are class reordering only. This is
the largest diff but lowest risk since it changes no class names, only
their order.
**Stack:** #9417 → #9427 → **this PR**
Fixes#9300 (partial — 3 of 3 rules)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9428-fix-enable-enforce-consistent-class-order-tailwind-lint-rule-31a6d73d3650811c9065f5178ba3e724)
by [Unito](https://www.unito.io)
## Summary
Enable `better-tailwindcss/enforce-canonical-classes` lint rule and
auto-fix all 611 violations across 173 files. Stacked on #9417.
## Changes
- **What**: Simplify Tailwind classes to canonical forms via `eslint
--fix`:
- `h-X w-X` → `size-X`
- `overflow-x-hidden overflow-y-hidden` → `overflow-hidden`
- and other canonical simplifications
- Enable `enforce-canonical-classes` as `'error'` in eslint config
## Review Focus
Mechanical auto-fix PR — all changes produced by `eslint --fix`. No
visual or behavioral changes; canonical forms are functionally
identical.
**Stack:** #9417 → **this PR** → PR 3 (class order)
Fixes#9300 (partial — 2 of 3 rules)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9427-fix-enable-enforce-canonical-classes-tailwind-lint-rule-31a6d73d365081a49340d7d4640ede45)
by [Unito](https://www.unito.io)
## Summary
Add `eslint-plugin-better-tailwindcss` to the ESLint toolchain for
Tailwind CSS v4 class linting.
## Changes
- **What**: Integrate `eslint-plugin-better-tailwindcss` (v4.3.1) with
the recommended config, pointed at the design-system CSS entry point for
v4 theme resolution. Five rules are enabled initially:
`enforce-canonical-classes`, `no-deprecated-classes`,
`no-conflicting-classes`, `no-duplicate-classes`,
`no-unnecessary-whitespace`. Three rules are disabled pending follow-up:
`no-unknown-classes` (needs PrimeIcon/custom class whitelisting),
`enforce-consistent-line-wrapping` (oxfmt conflict risk),
`enforce-consistent-class-order` (large batch change).
- **Dependencies**: `eslint-plugin-better-tailwindcss` ^4.3.1
- Fix conflicting `outline outline-1` classes in
`FormDropdownMenuActions.vue` (caught by the new
`no-conflicting-classes` rule).
## Review Focus
- Is the rule severity/enablement strategy appropriate for incremental
adoption?
- The 700 warnings (mostly `enforce-canonical-classes` and
`no-deprecated-classes`) are all auto-fixable via `eslint --fix` —
should we batch-fix them in this PR or a follow-up?
Fixes COM-15518
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9245-feat-add-eslint-plugin-better-tailwindcss-for-Tailwind-v4-linting-3136d73d365081df8a64dd55962d073f)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
- The input and output indicators are now plugged directly into the
`LGraphNode.vue` template. Care was taken to make implementation to have
low cost for performance and complexity when not in app mode setup.
- Context menu event handlers are added to each widget in vue mode
instead of resolving the target widget of an event
- Swap the nodeId passed by `useGraphNodeManager` to not include the
locator id. This id was never used and was incorrect since it didn't
resolve across nested subgraphs.
- Continued bug fixes for app mode as a whole.
Known issue: There is disparity of nodeId between litegraph (which
references the widget in the root graph) and vue (which promotes the
original widget). Efforts to reconcile are ongoing.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9259-Support-selection-app-inputs-and-outputs-from-vue-mode-3136d73d365081ae8e56e35bf6322409)
by [Unito](https://www.unito.io)
---------
Co-authored-by: pythongosssss <125205205+pythongosssss@users.noreply.github.com>
## Summary
- fix sizing of sidebars in app mode
- update feedback button to match design
- update job queue notification
- clickable queue spinner item to allow clear queue
- refactor mode out of store to specific workflow instance
- support different saved vs active mode
- other styling/layout tweaks
## Changes
- **What**: Changes the store to a composable and moves the mode state
to the workflow.
- This enables switching between tabs and maintaining the mode they were
in
## Screenshots (if applicable)
<img width="1866" height="1455" alt="image"
src="https://github.com/user-attachments/assets/f9a8cd36-181f-4948-b48c-dd27bd9127cf"
/>
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9137-App-mode-more-updates-fixes-3106d73d365081a18ccff6ffe24fdec7)
by [Unito](https://www.unito.io)
---------
Co-authored-by: github-actions <github-actions@github.com>
## Problem
When sidebar is positioned on the right, the properties panel also
appears on the right, causing both panels to compete for space and
creating a poor layout.
## Solution
Properties panel now dynamically positions itself opposite to the
sidebar:
- Sidebar left → Properties panel right (default)
- Sidebar right → Properties panel left
## Changes
- Modified `LiteGraphCanvasSplitterOverlay.vue` to conditionally render
properties panel based on sidebar location
- Updated splitter refresh key to recalculate layout when sidebar
position changes
- Added dynamic close button icon in `RightSidePanel.vue` that points in
the correct direction
## Testing
- Created E2E tests to verify positioning behavior
- Manually verified visual behavior in browser
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7647-feat-position-properties-panel-opposite-to-sidebar-2ce6d73d365081049683e74c8d03dbdd)
by [Unito](https://www.unito.io)
## Summary
Enhancing and further modernizing the UI, giving users more usable area
whilst keeping farmiliar positioning and feel of elements.
## Changes
- **What**: Significant restructure of the UI elements, changing
elements from large blocks to floating elements, updating:
- Side toolbar menu (floating style, supports small/normal mode,
combines to scroll on height overflow)
- Bottom tabs panel (floating style, tabs redesigned)
- Action bar (support for docking/undocking menu)
- Added login/user menu button to top right
- Restyled breadcrumbs (still collapse when overflows)
- Add litegraph support for fps info position (so it isn't covered by
the sidebar)
- **Breaking**:
- Removed various elements and added new ones, I have tested custom
sidebars, custom actions, etc but if scripts are inserting elements into
"other" elements they may have been (re)moved.
- Remove support for bottom menu
- Remove support for 2nd-row tabs
## Screenshots
<img width="1116" height="907" alt="ui"
src="https://github.com/user-attachments/assets/b040a215-67d3-4c88-8c4d-f402a16a34f6"
/>
https://github.com/user-attachments/assets/571dbda5-01ec-47e8-b235-ee1b88c93dd0
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5980-Floating-Menus-UI-rework-2866d73d3650810aac60cc1afe979b60)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
* refactor: move settingStore to platform/settings
Move src/stores/settingStore.ts to src/platform/settings/settingStore.ts
to separate platform infrastructure from domain logic following DDD principles.
Updates all import references across ~70 files to maintain compatibility.
* fix: update remaining settingStore imports after rebase
* fix: complete remaining settingStore import updates
* fix: update vi.mock paths for settingStore in tests
Update all test files to mock the new settingStore location at
@/platform/settings/settingStore instead of @/stores/settingStore
* fix: resolve remaining settingStore imports and unused imports after rebase
* fix: update settingStore mock path in SelectionToolbox test
Fix vi.mock path from @/stores/settingStore to @/platform/settings/settingStore
to resolve failing Load3D viewer button test.
* refactor: complete comprehensive settings migration to platform layer
This commit completes the migration of all settings-related code to the platform layer
as part of the Domain-Driven Design (DDD) architecture refactoring.
- constants/coreSettings.ts → platform/settings/constants/coreSettings.ts
- types/settingTypes.ts → platform/settings/types.ts
- stores/settingStore.ts → platform/settings/settingStore.ts (already moved)
- composables/setting/useSettingUI.ts → platform/settings/composables/useSettingUI.ts
- composables/setting/useSettingSearch.ts → platform/settings/composables/useSettingSearch.ts
- composables/useLitegraphSettings.ts → platform/settings/composables/useLitegraphSettings.ts
- components/dialog/content/SettingDialogContent.vue → platform/settings/components/SettingDialogContent.vue
- components/dialog/content/setting/SettingItem.vue → platform/settings/components/SettingItem.vue
- components/dialog/content/setting/SettingGroup.vue → platform/settings/components/SettingGroup.vue
- components/dialog/content/setting/SettingsPanel.vue → platform/settings/components/SettingsPanel.vue
- components/dialog/content/setting/ColorPaletteMessage.vue → platform/settings/components/ColorPaletteMessage.vue
- components/dialog/content/setting/ExtensionPanel.vue → platform/settings/components/ExtensionPanel.vue
- components/dialog/content/setting/ServerConfigPanel.vue → platform/settings/components/ServerConfigPanel.vue
- ~100+ import statements updated across the codebase
- Test file imports corrected
- Component imports fixed in dialog service and command menubar
- Composable imports updated in GraphCanvas.vue
```
src/platform/settings/
├── components/ # All settings UI components
├── composables/ # Settings-related composables
├── constants/ # Core settings definitions
├── types.ts # Settings type definitions
└── settingStore.ts # Central settings state management
```
✅ TypeScript compilation successful
✅ All tests passing (settings store, search functionality, UI components)
✅ Production build successful
✅ Domain boundaries properly established
This migration consolidates all settings functionality into a cohesive platform domain,
improving maintainability and following DDD principles for better code organization.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: format and lint after rebase conflict resolution
* fix: update remaining import paths to platform settings
- Fix browser test import: extensionAPI.spec.ts
- Fix script import: collect-i18n-general.ts
- Complete settings migration import path updates
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* temp: move tailwind calls out of the layer
* temp: ts tailwind config
* upgrade: Tailwind v4
This got a little out of hand.
Had to add a relative reference to the stylesheet in any component that uses @apply instead of the utility classes directly.
* upgrade: bg-opacity is now a modifier
* fix: Classic menu buttons assume a border
* Update test expectations [skip ci]
* fix: New preflight removal pattern
* fix: Skeletons don't have skin
* Update test expectations [skip ci]
* fix: Missing @reference
* [auto-fix] Apply ESLint and Prettier fixes
---------
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: GitHub Action <action@github.com>
* Basic side tool bar skeleton + Theme toggle (#164)
* Side bar skeleton
* Fix grid layout
* nit
* Add theme toggle logic
* Change primevue color theme to blue to match beta menu UI
* Add litegraph canvas splitter overlay (#177)
* Add vue wrapper
* Splitter overlay
* Move teleport to side bar comp
* Toolbar placeholder
* Move settings button from top menu to side bar (#178)
* Reverse relationship between splitter overlay and sidebar component (#180)
* Reverse relationship between splitter overlay and sidebar component
* nit
* Remove border on splitter
* Fix canvas shift (#186)
* Move queue/history display to side bar (#185)
* Side bar placeholder
* Pinia store for queue items
* Flatten task item
* Fix schema
* computed
* Switch running / pending order
* Use class-transformer
* nit
* Show display status
* Add tag severity style
* Add execution time
* nit
* Rename to execution success
* Add time display
* Sort queue desc order
* nit
* Add remove item feature
* Load workflow
* Add confirmation popup
* Add empty table placeholder
* Remove beta menu UI's queue button/list
* Add tests on litegraph widget text truncate (#191)
* Add tests on litegraph widget text truncate
* Updated screenshots
* Revert port change
* Remove screenshots
* Update test expectations [skip ci]
* Add back menu.settingsGroup for compatibility (#192)
* Close side bar on menu location set as disabled (#194)
* Remove placeholder side bar tabs (#196)
---------
Co-authored-by: bymyself <abolkonsky.rem@gmail.com>
Co-authored-by: github-actions <github-actions@github.com>