Files
ComfyUI_frontend/src/platform/assets/components/UploadModelUrlInput.vue
Alexander Brown c6f2ae3130 fix(upload-model): UI/UX improvements for Upload Model Dialog (#7969)
## Summary

Addresses UI/UX feedback on the Upload Model Dialog (BYOM feature).

## Changes

1. **Standardize link styling** - Use consistent `text-muted-foreground
underline` for all links in both URL input variants
2. **Increase warning/example text font size** - Changed from 12px
(`text-xs`) to 14px (`text-sm`) for better readability
3. **Fix padding inconsistency** - Aligned padding between model name
box and SingleSelect dropdown; moved "Not sure?" help text inline with
the label
4. **Add "Upload Another" button** - Allows users to upload multiple
models without closing and reopening the dialog

## Testing

- Verified link styling consistency across both Civitai and generic URL
input components
- Confirmed padding alignment in confirmation step
- Tested Upload Another button resets wizard to step 1

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7969-fix-upload-model-UI-UX-improvements-for-Upload-Model-Dialog-2e66d73d3650815c8184cedb3d02672d)
by [Unito](https://www.unito.io)
2026-01-12 17:25:01 -08:00

120 lines
3.8 KiB
Vue

<template>
<div class="flex flex-col justify-between h-full gap-6 text-sm">
<div class="flex flex-col gap-6">
<div class="flex flex-col gap-2">
<p class="m-0 text-foreground">
{{ $t('assetBrowser.uploadModelDescription1Generic') }}
</p>
<div class="m-0">
<p class="m-0 text-muted-foreground">
{{ $t('assetBrowser.uploadModelDescription2Generic') }}
</p>
<span class="inline-flex items-center gap-1 flex-wrap mt-2">
<span class="inline-flex items-center gap-1">
<img
:src="civitaiIcon"
:alt="$t('assetBrowser.providerCivitai')"
class="w-4 h-4"
/>
<a
:href="civitaiUrl"
target="_blank"
rel="noopener noreferrer"
class="text-muted-foreground underline"
>
{{ $t('assetBrowser.providerCivitai') }}</a
><span>,</span>
</span>
<span class="inline-flex items-center gap-1">
<img
:src="huggingFaceIcon"
:alt="$t('assetBrowser.providerHuggingFace')"
class="w-4 h-4"
/>
<a
:href="huggingFaceUrl"
target="_blank"
rel="noopener noreferrer"
class="text-muted-foreground underline"
>
{{ $t('assetBrowser.providerHuggingFace') }}
</a>
</span>
</span>
</div>
</div>
<div class="flex flex-col gap-2">
<div class="relative">
<InputText
v-model="url"
autofocus
:placeholder="$t('assetBrowser.genericLinkPlaceholder')"
class="w-full border-0 bg-secondary-background p-4 pr-10"
data-attr="upload-model-step1-url-input"
/>
<i
v-if="isValidUrl"
class="icon-[lucide--circle-check-big] absolute top-1/2 right-3 size-5 -translate-y-1/2 text-green-500"
/>
</div>
<p v-if="error" class="text-sm text-error">
{{ error }}
</p>
<p v-else-if="!flags.asyncModelUploadEnabled" class="text-foreground">
<i18n-t keypath="assetBrowser.maxFileSize" tag="span">
<template #size>
<span class="font-bold italic">{{
$t('assetBrowser.maxFileSizeValue')
}}</span>
</template>
</i18n-t>
</p>
</div>
</div>
<div class="text-sm text-muted">
{{ $t('assetBrowser.uploadModelHelpFooterText') }}
</div>
</div>
</template>
<script setup lang="ts">
import InputText from 'primevue/inputtext'
import { computed } from 'vue'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
import { civitaiImportSource } from '@/platform/assets/importSources/civitaiImportSource'
import { huggingfaceImportSource } from '@/platform/assets/importSources/huggingfaceImportSource'
import { validateSourceUrl } from '@/platform/assets/utils/importSourceUtil'
const { flags } = useFeatureFlags()
const props = defineProps<{
modelValue: string
error?: string
}>()
const emit = defineEmits<{
'update:modelValue': [value: string]
}>()
const url = computed({
get: () => props.modelValue,
set: (value: string) => emit('update:modelValue', value)
})
const importSources = [civitaiImportSource, huggingfaceImportSource]
const isValidUrl = computed(() => {
const trimmedUrl = url.value.trim()
if (!trimmedUrl) return false
return importSources.some((source) => validateSourceUrl(trimmedUrl, source))
})
const civitaiIcon = '/assets/images/civitai.svg'
const civitaiUrl = 'https://civitai.com/models'
const huggingFaceIcon = '/assets/images/hf-logo.svg'
const huggingFaceUrl = 'https://huggingface.co'
</script>