Decouple Desktop UI into monorepo app (#5912)

## Summary

Extracts desktop UI into apps/desktop-ui package with minimal changes.

## Changes

- **What**:
- Separates desktop-specific code into standalone package with
independent Vite config, router, and i18n
- Drastically simplifies the main app router by removing all desktop
routes
  - Adds a some code duplication, most due to the existing design
- Some duplication can be refactored to be *simpler* on either side - no
need to split things by `isElectron()`
  - Rudimentary storybook support has been added
- **Breaking**: Stacked PR for publishing must be merged before this PR
makes it to stable core (but publishing _could_ be done manually)
  - #5915
- **Dependencies**: Takes full advantage of pnpm catalog. No additional
dependencies added.

## Review Focus

- Should be no changes to normal frontend operation
- Scripts added to root package.json are acceptable
- The duplication in this PR is copied as is, wherever possible. Any
corrections or fix-ups beyond the scope of simply migrating the
functionality as-is, can be addressed in later PRs. That said, if any
changes are made, it instantly becomes more difficult to separate the
duplicated code out into a shared utility.
  - Tracking issue to address concerns: #5925

### i18n

Fixing i18n is out of scope for this PR. It is a larger task that we
should consider carefully and implement properly. Attempting to isolate
the desktop i18n and duplicate the _current_ localisation scripts would
be wasted energy.
This commit is contained in:
filtered
2025-10-05 16:04:27 +11:00
committed by GitHub
parent ac9ebe1266
commit 07a74e3cdc
72 changed files with 1213 additions and 101 deletions

View File

@@ -0,0 +1,103 @@
<template>
<div
class="grid grid-rows-[1fr_auto_auto_1fr] w-full max-w-3xl mx-auto h-[40rem] select-none"
>
<h2 class="font-inter font-bold text-3xl text-neutral-100 text-center">
{{ $t('install.gpuPicker.title') }}
</h2>
<!-- GPU Selection buttons - takes up remaining space and centers content -->
<div class="flex-1 flex gap-8 justify-center items-center">
<!-- Apple Metal / NVIDIA -->
<HardwareOption
v-if="platform === 'darwin'"
:image-path="'/assets/images/apple-mps-logo.png'"
placeholder-text="Apple Metal"
subtitle="Apple Metal"
:value="'mps'"
:selected="selected === 'mps'"
:recommended="true"
@click="pickGpu('mps')"
/>
<HardwareOption
v-else
:image-path="'/assets/images/nvidia-logo-square.jpg'"
placeholder-text="NVIDIA"
:subtitle="$t('install.gpuPicker.nvidiaSubtitle')"
:value="'nvidia'"
:selected="selected === 'nvidia'"
:recommended="true"
@click="pickGpu('nvidia')"
/>
<!-- CPU -->
<HardwareOption
placeholder-text="CPU"
:subtitle="$t('install.gpuPicker.cpuSubtitle')"
:value="'cpu'"
:selected="selected === 'cpu'"
@click="pickGpu('cpu')"
/>
<!-- Manual Install -->
<HardwareOption
placeholder-text="Manual Install"
:subtitle="$t('install.gpuPicker.manualSubtitle')"
:value="'unsupported'"
:selected="selected === 'unsupported'"
@click="pickGpu('unsupported')"
/>
</div>
<div class="pt-12 px-24 h-16">
<div v-show="showRecommendedBadge" class="flex items-center gap-2">
<Tag
:value="$t('install.gpuPicker.recommended')"
class="bg-neutral-300 text-neutral-900 rounded-full text-sm font-bold px-2 py-[1px]"
/>
<i-lucide:badge-check class="text-neutral-300 text-lg" />
</div>
</div>
<div class="text-neutral-300 px-24">
<p v-show="descriptionText" class="leading-relaxed">
{{ descriptionText }}
</p>
</div>
</div>
</template>
<script setup lang="ts">
import type { TorchDeviceType } from '@comfyorg/comfyui-electron-types'
import Tag from 'primevue/tag'
import { computed } from 'vue'
import HardwareOption from '@/components/install/HardwareOption.vue'
import { st } from '@/i18n'
import { electronAPI } from '@/utils/envUtil'
const selected = defineModel<TorchDeviceType | null>('device', {
required: true
})
const electron = electronAPI()
const platform = electron.getPlatform()
const showRecommendedBadge = computed(
() => selected.value === 'mps' || selected.value === 'nvidia'
)
const descriptionKeys = {
mps: 'appleMetal',
nvidia: 'nvidia',
cpu: 'cpu',
unsupported: 'manual'
} as const
const descriptionText = computed(() => {
const key = selected.value ? descriptionKeys[selected.value] : undefined
return st(`install.gpuPicker.${key}Description`, '')
})
const pickGpu = (value: TorchDeviceType) => {
selected.value = value
}
</script>