mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-08 17:10:07 +00:00
## 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>
130 lines
3.9 KiB
Vue
130 lines
3.9 KiB
Vue
<template>
|
|
<div class="flex h-full flex-col">
|
|
<Tabs
|
|
:key="$i18n.locale"
|
|
v-model:value="bottomPanelStore.activeBottomPanelTabId"
|
|
style="--p-tabs-tablist-background: var(--comfy-menu-bg)"
|
|
>
|
|
<TabList
|
|
pt:tab-list="border-none h-full flex items-center py-2 border-b-1 border-solid"
|
|
class="bg-transparent"
|
|
>
|
|
<div class="flex w-full justify-between">
|
|
<div class="tabs-container">
|
|
<Tab
|
|
v-for="tab in bottomPanelStore.bottomPanelTabs"
|
|
:key="tab.id"
|
|
:value="tab.id"
|
|
class="m-1 mx-2 border-none"
|
|
:class="{
|
|
'tab-list-single-item':
|
|
bottomPanelStore.bottomPanelTabs.length === 1
|
|
}"
|
|
:pt:root="
|
|
(x: TabPassThroughMethodOptions) => ({
|
|
class: {
|
|
'p-3 rounded-lg': true,
|
|
'pointer-events-none':
|
|
bottomPanelStore.bottomPanelTabs.length === 1
|
|
},
|
|
style: {
|
|
color: 'var(--fg-color)',
|
|
backgroundColor:
|
|
!x.context.active ||
|
|
bottomPanelStore.bottomPanelTabs.length === 1
|
|
? ''
|
|
: 'var(--bg-color)'
|
|
}
|
|
})
|
|
"
|
|
>
|
|
<span class="font-normal">
|
|
{{ getTabDisplayTitle(tab) }}
|
|
</span>
|
|
</Tab>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<Button
|
|
v-if="isShortcutsTabActive"
|
|
:label="$t('shortcuts.manageShortcuts')"
|
|
icon="pi pi-cog"
|
|
severity="secondary"
|
|
size="small"
|
|
text
|
|
@click="openKeybindingSettings"
|
|
/>
|
|
<Button
|
|
class="justify-self-end"
|
|
icon="pi pi-times"
|
|
severity="secondary"
|
|
size="small"
|
|
text
|
|
@click="closeBottomPanel"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</TabList>
|
|
</Tabs>
|
|
<!-- h-0 to force the div to grow -->
|
|
<div class="h-0 grow">
|
|
<ExtensionSlot
|
|
v-if="
|
|
bottomPanelStore.bottomPanelVisible &&
|
|
bottomPanelStore.activeBottomPanelTab
|
|
"
|
|
:extension="bottomPanelStore.activeBottomPanelTab"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import Button from 'primevue/button'
|
|
import Tab from 'primevue/tab'
|
|
import type { TabPassThroughMethodOptions } from 'primevue/tab'
|
|
import TabList from 'primevue/tablist'
|
|
import Tabs from 'primevue/tabs'
|
|
import { computed } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
import ExtensionSlot from '@/components/common/ExtensionSlot.vue'
|
|
import { useDialogService } from '@/services/dialogService'
|
|
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'
|
|
import type { BottomPanelExtension } from '@/types/extensionTypes'
|
|
|
|
const bottomPanelStore = useBottomPanelStore()
|
|
const dialogService = useDialogService()
|
|
const { t } = useI18n()
|
|
|
|
const isShortcutsTabActive = computed(() => {
|
|
const activeTabId = bottomPanelStore.activeBottomPanelTabId
|
|
return (
|
|
activeTabId === 'shortcuts-essentials' ||
|
|
activeTabId === 'shortcuts-view-controls'
|
|
)
|
|
})
|
|
|
|
const shouldCapitalizeTab = (tabId: string): boolean => {
|
|
return tabId !== 'shortcuts-essentials' && tabId !== 'shortcuts-view-controls'
|
|
}
|
|
|
|
const getTabDisplayTitle = (tab: BottomPanelExtension): string => {
|
|
const title = tab.titleKey ? t(tab.titleKey) : tab.title || ''
|
|
return shouldCapitalizeTab(tab.id) ? title.toUpperCase() : title
|
|
}
|
|
|
|
const openKeybindingSettings = async () => {
|
|
dialogService.showSettingsDialog('keybinding')
|
|
}
|
|
|
|
const closeBottomPanel = () => {
|
|
bottomPanelStore.activePanel = null
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
:deep(.p-tablist-active-bar) {
|
|
display: none;
|
|
}
|
|
</style>
|