Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add desktop custom window / native window controls #1856

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/assets/images/Comfy_Logo_x256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import BlockUI from 'primevue/blockui'
import ProgressSpinner from 'primevue/progressspinner'
import GlobalDialog from '@/components/dialog/GlobalDialog.vue'
import { useEventListener } from '@vueuse/core'
import { isElectron } from './utils/envUtil'

const workspaceStore = useWorkspaceStore()
const isLoading = computed<boolean>(() => workspaceStore.spinner)
Expand All @@ -28,5 +29,10 @@ useEventListener(window, 'keyup', handleKey)
onMounted(() => {
window['__COMFYUI_FRONTEND_VERSION__'] = config.app_version
console.log('ComfyUI Front-end version:', config.app_version)

if (isElectron()) {
// Enable CSS selectors
document.documentElement.dataset['platform'] = 'electron'
}
})
</script>
8 changes: 8 additions & 0 deletions src/assets/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -704,3 +704,11 @@ audio.comfy-audio.empty-audio-widget {
.p-tree-node-content {
padding: var(--comfy-tree-explorer-item-padding) !important;
}

.app-drag {
app-region: drag;
}

.no-drag {
app-region: no-drag;
}
4 changes: 2 additions & 2 deletions src/components/MenuHamburger.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ const positionCSS = computed<CSSProperties>(() =>
// 'Bottom' menuSetting shows the hamburger button in the bottom right corner
// 'Disabled', 'Top' menuSetting shows the hamburger button in the top right corner
menuSetting.value === 'Bottom'
? { bottom: '0px', right: '0px' }
: { top: '0px', right: '0px' }
? { bottom: '0', right: '0' }
: { top: '0', right: 'calc(100% - env(titlebar-area-width, 100%))' }
)
</script>

Expand Down
63 changes: 62 additions & 1 deletion src/components/topbar/TopMenubar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ import BottomPanelToggleButton from '@/components/topbar/BottomPanelToggleButton
import { computed, onMounted, provide, ref } from 'vue'
import { useSettingStore } from '@/stores/settingStore'
import { app } from '@/scripts/app'
import { useEventBus } from '@vueuse/core'
import { useEventBus, useResizeObserver } from '@vueuse/core'
import { useWorkspaceStore } from '@/stores/workspaceStore'
import { electronAPI, isElectron } from '@/utils/envUtil'

const workspaceState = useWorkspaceStore()
const settingStore = useSettingStore()
Expand Down Expand Up @@ -72,6 +73,22 @@ eventBus.on((event: string, payload: any) => {
isDroppable.value = payload.isOverlapping && payload.isDragging
}
})

/** Height of titlebar on desktop. */
if (isElectron()) {
let desktopHeight = 0

useResizeObserver(topMenuRef, (entries) => {
if (settingStore.get('Comfy.UseNewMenu') !== 'Top') return

const [entry] = entries
const { height } = entry.contentRect
if (desktopHeight === height) return

electronAPI().changeTheme({ height })
desktopHeight = height
})
}
</script>

<style scoped>
Expand Down Expand Up @@ -107,3 +124,47 @@ eventBus.on((event: string, payload: any) => {
cursor: default;
}
</style>

<style>
/* Custom window styling */
:root[data-platform='electron'] {
.comfyui-logo {
display: flex;
align-items: center;
gap: 0.5rem;
margin: 0.25rem 0.5rem;

&::before {
content: '';
width: 1.75rem;
height: 1.75rem;
background: url('/assets/images/Comfy_Logo_x256.png') no-repeat;
background-size: contain;
}
}

.comfyui-body-top {
.comfyui-menu {
app-region: drag;
padding-right: calc(100% - env(titlebar-area-width, 0));
}

.comfyui-menu::after {
content: '';
height: calc(100% - 0.75rem);
width: 2px;
background-color: var(--p-navigation-item-icon-color);
display: block;
margin-left: 1rem;
margin-right: 1rem;
}
}

button,
.p-menubar,
.comfyui-menu-right > *,
.actionbar {
app-region: no-drag;
}
}
</style>
10 changes: 9 additions & 1 deletion src/hooks/coreCommandHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
LGraphGroup
} from '@comfyorg/litegraph'
import { useSearchBoxStore } from '@/stores/workspace/searchBoxStore'
import { isElectron, electronAPI } from '@/utils/envUtil'

export function useCoreCommands(): ComfyCommand[] {
const getTracker = () => useWorkflowStore()?.activeWorkflow?.changeTracker
Expand Down Expand Up @@ -414,12 +415,19 @@ export function useCoreCommands(): ComfyCommand[] {
return () => {
const settingStore = useSettingStore()
const currentTheme = settingStore.get('Comfy.ColorPalette')
if (isDarkMode(currentTheme)) {
const useLightMode = isDarkMode(currentTheme)
if (useLightMode) {
previousDarkTheme = currentTheme
settingStore.set('Comfy.ColorPalette', 'light')
} else {
settingStore.set('Comfy.ColorPalette', previousDarkTheme)
}
if (isElectron()) {
electronAPI().changeTheme({
color: '#00000000',
symbolColor: useLightMode ? '#333' : '#ddd'
})
}
}
})()
},
Expand Down
10 changes: 8 additions & 2 deletions src/views/DownloadGitView.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<template>
<div
class="font-sans w-screen h-screen mx-0 grid place-items-center justify-center items-center text-neutral-900 bg-neutral-300 pointer-events-auto"
class="app-drag font-sans w-screen h-screen mx-0 grid place-items-center justify-center items-center text-neutral-900 bg-neutral-300 pointer-events-auto"
>
<div
class="col-start-1 h-screen row-start-1 place-content-center mx-auto overflow-y-auto"
>
<div
class="max-w-screen-sm flex flex-col gap-8 p-8 bg-[url('/assets/images/Git-Logo-White.svg')] bg-no-repeat bg-right-top bg-origin-padding"
class="no-drag max-w-screen-sm flex flex-col gap-8 p-8 bg-[url('/assets/images/Git-Logo-White.svg')] bg-no-repeat bg-right-top bg-origin-padding"
>
<!-- Header -->
<h1 class="mt-24 text-4xl font-bold text-red-500">
Expand Down Expand Up @@ -48,7 +48,9 @@
</template>

<script setup lang="ts">
import { electronAPI } from '@/utils/envUtil'
import Button from 'primevue/button'
import { onMounted } from 'vue'
import { useRouter } from 'vue-router'

const openGitDownloads = () => {
Expand All @@ -60,4 +62,8 @@ const skipGit = () => {
const router = useRouter()
router.push('install')
}

onMounted(() => {
electronAPI()?.changeTheme({ color: '#d4d4d4', symbolColor: '#171717' })
})
</script>
18 changes: 18 additions & 0 deletions src/views/GraphView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ import { SERVER_CONFIG_ITEMS } from '@/constants/serverConfig'
import { useMenuItemStore } from '@/stores/menuItemStore'
import { useCommandStore } from '@/stores/commandStore'
import { useCoreCommands } from '@/hooks/coreCommandHooks'
import {
defaultColorPalette,
getColorPalette
} from '@/extensions/core/colorPalette'
import { electronAPI, isElectron } from '@/utils/envUtil'

setupAutoQueueHandler()

Expand All @@ -51,6 +56,7 @@ const settingStore = useSettingStore()
const executionStore = useExecutionStore()

const theme = computed<string>(() => settingStore.get('Comfy.ColorPalette'))
const defaultCssVars = defaultColorPalette.colors.comfy_base

watch(
theme,
Expand All @@ -62,6 +68,18 @@ watch(
} else {
document.body.classList.remove(DARK_THEME_CLASS)
}

// Native window control theme
if (isElectron()) {
const cssVars = getColorPalette(newTheme).colors.comfy_base
let color = cssVars['comfy-menu-bg'] ?? defaultCssVars['comfy-menu-bg']
if (color.startsWith('#')) {
if (color.length === 4) color = `#${color.substring(1).repeat(2)}`
color = `#${color.substring(1, 7)}00`
}
const symbolColor = cssVars['input-text'] ?? defaultCssVars['input-text']
electronAPI().changeTheme({ color, symbolColor })
}
},
{ immediate: true }
)
Expand Down
10 changes: 7 additions & 3 deletions src/views/InstallView.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<div
class="font-sans flex flex-col items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto"
class="app-drag font-sans flex flex-col items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto"
>
<Stepper class="mt-[5vh] 2xl:mt-[20vh]" value="1">
<Stepper class="no-drag mt-[5vh] 2xl:mt-[20vh]" value="1">
<StepList>
<Step value="1" :disabled="hasError">
{{ $t('install.installLocation') }}
Expand Down Expand Up @@ -88,7 +88,7 @@ import InstallLocationPicker from '@/components/install/InstallLocationPicker.vu
import MigrationPicker from '@/components/install/MigrationPicker.vue'
import DesktopSettingsConfiguration from '@/components/install/DesktopSettingsConfiguration.vue'
import { electronAPI } from '@/utils/envUtil'
import { ref, computed, toRaw } from 'vue'
import { ref, computed, toRaw, onMounted } from 'vue'
import { useRouter } from 'vue-router'

const installPath = ref('')
Expand All @@ -114,6 +114,10 @@ const install = () => {
electronAPI().installComfyUI(options)
router.push('/server-start')
}

onMounted(() => {
electronAPI()?.changeTheme({ color: '#171717', symbolColor: '#d4d4d4' })
})
</script>

<style scoped>
Expand Down
10 changes: 8 additions & 2 deletions src/views/NotSupportedView.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<div
class="font-sans w-screen h-screen flex items-center m-0 text-neutral-900 bg-neutral-300 pointer-events-auto"
class="app-drag font-sans w-screen h-screen flex items-center m-0 text-neutral-900 bg-neutral-300 pointer-events-auto"
>
<div class="flex-grow flex items-center justify-center">
<div class="no-drag flex-grow flex items-center justify-center">
<div class="flex flex-col gap-8 p-8">
<!-- Header -->
<h1 class="text-4xl font-bold text-red-500">
Expand Down Expand Up @@ -58,7 +58,9 @@
</template>

<script setup lang="ts">
import { electronAPI } from '@/utils/envUtil'
import Button from 'primevue/button'
import { onMounted } from 'vue'
import { useRouter } from 'vue-router'

const openDocs = () => {
Expand All @@ -76,4 +78,8 @@ const router = useRouter()
const continueToInstall = () => {
router.push('/install')
}

onMounted(() => {
electronAPI()?.changeTheme({ color: '#d4d4d4', symbolColor: '#171717' })
})
</script>
9 changes: 5 additions & 4 deletions src/views/ServerStartView.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<template>
<div
class="font-sans flex flex-col justify-center items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto"
class="app-drag font-sans flex flex-col justify-center items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto"
>
<h2 class="text-2xl font-bold">
<h2 class="text-2xl font-bold select-none">
{{ t(`serverStart.process.${status}`) }}
<span v-if="status === ProgressStatus.ERROR">
v{{ electronVersion }}
</span>
</h2>
<div
v-if="status === ProgressStatus.ERROR"
class="flex items-center my-4 gap-2"
class="no-drag flex items-center my-4 gap-2"
>
<Button
icon="pi pi-flag"
Expand All @@ -30,7 +30,7 @@
@click="reinstall"
/>
</div>
<BaseTerminal @created="terminalCreated" />
<BaseTerminal class="no-drag" @created="terminalCreated" />
</div>
</template>

Expand Down Expand Up @@ -82,6 +82,7 @@ onMounted(async () => {
electron.sendReady()
electron.onProgressUpdate(updateProgress)
electronVersion.value = await electron.getElectronVersion()
electron.changeTheme({ color: '#171717', symbolColor: '#d4d4d4' })
})
</script>

Expand Down
7 changes: 5 additions & 2 deletions src/views/UserSelectView.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<template>
<div
id="comfy-user-selection"
class="font-sans flex flex-col items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto"
class="app-drag font-sans flex flex-col items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto"
>
<main
class="mt-[5vh] 2xl:mt-[20vh] min-w-84 relative rounded-lg bg-[var(--comfy-menu-bg)] p-5 px-10 shadow-lg"
class="no-drag mt-[5vh] 2xl:mt-[20vh] min-w-84 relative rounded-lg bg-[var(--comfy-menu-bg)] p-5 px-10 shadow-lg"
>
<h1 class="my-2.5 mb-7 font-normal">ComfyUI</h1>
<form class="flex w-full flex-col items-center">
Expand Down Expand Up @@ -49,6 +49,7 @@ import Message from 'primevue/message'
import { User, useUserStore } from '@/stores/userStore'
import { useRouter } from 'vue-router'
import { computed, onMounted, ref } from 'vue'
import { electronAPI } from '@/utils/envUtil'

const userStore = useUserStore()
const router = useRouter()
Expand Down Expand Up @@ -83,6 +84,8 @@ const login = async () => {
}

onMounted(async () => {
electronAPI()?.changeTheme({ color: '#171717', symbolColor: '#d4d4d4' })

if (!userStore.initialized) {
await userStore.initialize()
}
Expand Down
10 changes: 8 additions & 2 deletions src/views/WelcomeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div
class="font-sans flex flex-col justify-center items-center h-screen m-0 text-neutral-300 bg-neutral-900 dark-theme pointer-events-auto"
>
<div class="flex flex-col items-center justify-center gap-8 p-8">
<div class="app-drag flex flex-col items-center justify-center gap-8 p-8">
<!-- Header -->
<h1 class="animated-gradient-text text-glow select-none">
{{ $t('welcome.title') }}
Expand All @@ -16,20 +16,26 @@
size="large"
rounded
@click="navigateTo('/install')"
class="p-4 text-lg fade-in-up"
class="no-drag p-4 text-lg fade-in-up"
/>
</div>
</div>
</template>

<script setup lang="ts">
import { electronAPI } from '@/utils/envUtil'
import Button from 'primevue/button'
import { onMounted } from 'vue'
import { useRouter } from 'vue-router'

const router = useRouter()
const navigateTo = (path: string) => {
router.push(path)
}

onMounted(() => {
electronAPI()?.changeTheme({ color: '#171717', symbolColor: '#d4d4d4' })
})
</script>

<style scoped>
Expand Down
Loading