Component: Button Migration 3: IconTextButton (#7603)

## Summary

Replace all the `IconTextButton`s with `Button`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7603-WIP-Component-Button-Migraion-3-IconTextButton-2cd6d73d365081b7b742fa2172dc2ba8)
by [Unito](https://www.unito.io)
This commit is contained in:
Alexander Brown
2025-12-18 16:09:56 -08:00
committed by GitHub
parent 6244cf1008
commit 2c26fbb550
26 changed files with 338 additions and 754 deletions

View File

@@ -29,19 +29,18 @@
:placeholder="$t('g.searchPlaceholder')"
class="max-w-96"
/>
<IconTextButton
<Button
v-if="isUploadButtonEnabled"
type="accent"
size="md"
class="!h-10 [&>span]:hidden md:[&>span]:inline"
variant="primary"
:size="breakpoints.md ? 'md' : 'icon'"
data-attr="upload-model-button"
:label="$t('assetBrowser.uploadModel')"
:on-click="showUploadDialog"
@click="showUploadDialog"
>
<template #icon>
<i class="icon-[lucide--folder-input]" />
</template>
</IconTextButton>
<i class="icon-[lucide--folder-input]" />
<span class="hidden md:inline">{{
$t('assetBrowser.uploadModel')
}}</span>
</Button>
</div>
</template>
@@ -64,12 +63,16 @@
</template>
<script setup lang="ts">
import { useAsyncState } from '@vueuse/core'
import {
breakpointsTailwind,
useAsyncState,
useBreakpoints
} from '@vueuse/core'
import { computed, provide, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import IconTextButton from '@/components/button/IconTextButton.vue'
import SearchBox from '@/components/common/SearchBox.vue'
import Button from '@/components/ui/button/Button.vue'
import BaseModalLayout from '@/components/widget/layout/BaseModalLayout.vue'
import LeftSidePanel from '@/components/widget/panel/LeftSidePanel.vue'
import AssetFilterBar from '@/platform/assets/components/AssetFilterBar.vue'
@@ -99,6 +102,8 @@ const emit = defineEmits<{
close: []
}>()
const breakpoints = useBreakpoints(breakpointsTailwind)
provide(OnCloseKey, props.onClose ?? (() => {}))
const fetchAssets = async () => {

View File

@@ -43,26 +43,24 @@
>
<MoreButton ref="dropdown-menu-button" size="sm">
<template #default>
<IconTextButton
:label="$t('g.rename')"
type="secondary"
<Button
variant="secondary"
size="md"
class="justify-start"
@click="startAssetRename"
>
<template #icon>
<i class="icon-[lucide--pencil]" />
</template>
</IconTextButton>
<IconTextButton
:label="$t('g.delete')"
type="secondary"
<i class="icon-[lucide--pencil]" />
<span>{{ $t('g.rename') }}</span>
</Button>
<Button
variant="secondary"
size="md"
class="justify-start"
@click="confirmDeletion"
>
<template #icon>
<i class="icon-[lucide--trash-2]" />
</template>
</IconTextButton>
<i class="icon-[lucide--trash-2]" />
<span>{{ $t('g.delete') }}</span>
</Button>
</template>
</MoreButton>
</IconGroup>
@@ -121,10 +119,10 @@ import { computed, ref, toValue, useId, useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
import IconGroup from '@/components/button/IconGroup.vue'
import IconTextButton from '@/components/button/IconTextButton.vue'
import MoreButton from '@/components/button/MoreButton.vue'
import EditableText from '@/components/common/EditableText.vue'
import { showConfirmDialog } from '@/components/dialog/confirm/confirmDialog'
import Button from '@/components/ui/button/Button.vue'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
import AssetBadgeGroup from '@/platform/assets/components/AssetBadgeGroup.vue'
import type { AssetDisplayItem } from '@/platform/assets/composables/useAssetBrowser'

View File

@@ -70,19 +70,17 @@
<!-- Output count (top-right) -->
<template v-if="showOutputCount" #top-right>
<IconTextButton
<Button
v-tooltip.top.pt:pointer-events-none="
$t('mediaAsset.actions.seeMoreOutputs')
"
type="secondary"
variant="secondary"
size="sm"
:label="String(outputCount)"
@click.stop="handleOutputCountClick"
>
<template #icon>
<i class="icon-[lucide--layers] size-4" />
</template>
</IconTextButton>
<i class="icon-[lucide--layers] size-4" />
<span>{{ outputCount }}</span>
</Button>
</template>
</CardTop>
</template>
@@ -130,7 +128,6 @@ import { useElementHover, whenever } from '@vueuse/core'
import { computed, defineAsyncComponent, provide, ref, toRef } from 'vue'
import IconGroup from '@/components/button/IconGroup.vue'
import IconTextButton from '@/components/button/IconTextButton.vue'
import CardBottom from '@/components/card/CardBottom.vue'
import CardContainer from '@/components/card/CardContainer.vue'
import CardTop from '@/components/card/CardTop.vue'

View File

@@ -13,18 +13,17 @@
}"
>
<template #item="{ item, props }">
<IconTextButton
type="secondary"
size="full-width"
:label="
typeof item.label === 'function' ? item.label() : (item.label ?? '')
"
<Button
variant="secondary"
size="sm"
class="w-full justify-start"
v-bind="props.action"
>
<template #icon>
<i :class="item.icon" class="size-4" />
</template>
</IconTextButton>
<i :class="item.icon" class="size-4" />
<span>{{
typeof item.label === 'function' ? item.label() : (item.label ?? '')
}}</span>
</Button>
</template>
</ContextMenu>
</template>
@@ -34,9 +33,9 @@ import { onClickOutside } from '@vueuse/core'
import ContextMenu from 'primevue/contextmenu'
import type { MenuItem } from 'primevue/menuitem'
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import IconTextButton from '@/components/button/IconTextButton.vue'
import { t } from '@/i18n'
import Button from '@/components/ui/button/Button.vue'
import { isCloud } from '@/platform/distribution/types'
import { supportsWorkflowMetadata } from '@/platform/workflow/utils/workflowExtractionUtil'
import { detectNodeTypeFromFilename } from '@/utils/loaderNodeUtil'
@@ -60,6 +59,7 @@ const emit = defineEmits<{
const contextMenu = ref<InstanceType<typeof ContextMenu>>()
const actions = useMediaAssetActions()
const { t } = useI18n()
// Close context menu when clicking outside
onClickOutside(

View File

@@ -25,10 +25,9 @@
>
<template #default="{ close }">
<MediaAssetSortMenu
:sort-by="sortBy"
v-model:sort-by="sortBy"
:show-generation-time-sort
:close="close"
@update:sort-by="handleSortChange"
/>
</template>
</AssetSortButton>
@@ -43,30 +42,25 @@ import MediaAssetFilterButton from './MediaAssetFilterButton.vue'
import MediaAssetFilterMenu from './MediaAssetFilterMenu.vue'
import AssetSortButton from './MediaAssetSortButton.vue'
import MediaAssetSortMenu from './MediaAssetSortMenu.vue'
import type { SortBy } from './MediaAssetSortMenu.vue'
const { showGenerationTimeSort = false } = defineProps<{
searchQuery: string
sortBy: 'newest' | 'oldest' | 'longest' | 'fastest'
showGenerationTimeSort?: boolean
mediaTypeFilters: string[]
}>()
const emit = defineEmits<{
'update:searchQuery': [value: string]
'update:sortBy': [value: 'newest' | 'oldest' | 'longest' | 'fastest']
'update:mediaTypeFilters': [value: string[]]
}>()
const sortBy = defineModel<SortBy>('sortBy', { required: true })
const handleSearchChange = (value: string | undefined) => {
emit('update:searchQuery', value ?? '')
}
const handleSortChange = (
value: 'newest' | 'oldest' | 'longest' | 'fastest'
) => {
emit('update:sortBy', value)
}
const handleMediaTypeFiltersChange = (value: string[]) => {
emit('update:mediaTypeFilters', value)
}

View File

@@ -1,74 +1,59 @@
<template>
<div class="flex flex-col">
<IconTextButton
type="transparent"
icon-position="right"
:label="$t('sideToolbar.mediaAssets.sortNewestFirst')"
<Button
variant="textonly"
class="justify-start"
@click="handleSortChange('newest')"
>
<template #icon>
<i v-if="sortBy === 'newest'" class="icon-[lucide--check] size-4" />
</template>
</IconTextButton>
<span>{{ $t('sideToolbar.mediaAssets.sortNewestFirst') }}</span>
<i v-if="sortBy === 'newest'" class="icon-[lucide--check] size-4" />
</Button>
<IconTextButton
type="transparent"
icon-position="right"
:label="$t('sideToolbar.mediaAssets.sortOldestFirst')"
<Button
variant="textonly"
class="justify-start"
@click="handleSortChange('oldest')"
>
<template #icon>
<i v-if="sortBy === 'oldest'" class="icon-[lucide--check] size-4" />
</template>
</IconTextButton>
<span>{{ $t('sideToolbar.mediaAssets.sortOldestFirst') }}</span>
<i v-if="sortBy === 'oldest'" class="icon-[lucide--check] size-4" />
</Button>
<template v-if="showGenerationTimeSort">
<IconTextButton
type="transparent"
icon-position="right"
:label="$t('sideToolbar.mediaAssets.sortLongestFirst')"
<Button
variant="textonly"
class="justify-start"
@click="handleSortChange('longest')"
>
<template #icon>
<i v-if="sortBy === 'longest'" class="icon-[lucide--check] size-4" />
</template>
</IconTextButton>
<span>{{ $t('sideToolbar.mediaAssets.sortLongestFirst') }}</span>
<i v-if="sortBy === 'longest'" class="icon-[lucide--check] size-4" />
</Button>
<IconTextButton
type="transparent"
icon-position="right"
:label="$t('sideToolbar.mediaAssets.sortFastestFirst')"
<Button
variant="textonly"
class="justify-start"
@click="handleSortChange('fastest')"
>
<template #icon>
<i v-if="sortBy === 'fastest'" class="icon-[lucide--check] size-4" />
</template>
</IconTextButton>
<span>{{ $t('sideToolbar.mediaAssets.sortFastestFirst') }}</span>
<i v-if="sortBy === 'fastest'" class="icon-[lucide--check] size-4" />
</Button>
</template>
</div>
</template>
<script setup lang="ts">
import IconTextButton from '@/components/button/IconTextButton.vue'
import Button from '@/components/ui/button/Button.vue'
const {
sortBy,
close,
showGenerationTimeSort = false
} = defineProps<{
sortBy: 'newest' | 'oldest' | 'longest' | 'fastest'
export type SortBy = 'newest' | 'oldest' | 'longest' | 'fastest'
const { close, showGenerationTimeSort = false } = defineProps<{
close: () => void
showGenerationTimeSort?: boolean
}>()
const emit = defineEmits<{
'update:sortBy': [value: 'newest' | 'oldest' | 'longest' | 'fastest']
}>()
const sortBy = defineModel<SortBy>('sortBy', { required: true })
const handleSortChange = (
value: 'newest' | 'oldest' | 'longest' | 'fastest'
) => {
emit('update:sortBy', value)
const handleSortChange = (value: SortBy) => {
sortBy.value = value
close()
}
</script>

View File

@@ -1,18 +1,16 @@
<template>
<div class="flex justify-end gap-2 w-full">
<IconTextButton
<Button
v-if="currentStep === 1"
:label="$t('assetBrowser.uploadModelHowDoIFindThis')"
type="transparent"
size="md"
class="mr-auto underline text-muted-foreground"
variant="muted-textonly"
size="lg"
class="mr-auto underline"
data-attr="upload-model-step1-help-link"
@click="showVideoHelp = true"
>
<template #icon>
<i class="icon-[lucide--circle-question-mark]" />
</template>
</IconTextButton>
<i class="icon-[lucide--circle-question-mark]" />
<span>{{ $t('assetBrowser.uploadModelHowDoIFindThis') }}</span>
</Button>
<Button
v-if="currentStep === 1"
variant="muted-textonly"
@@ -35,38 +33,31 @@
</Button>
<span v-else />
<IconTextButton
<Button
v-if="currentStep === 1"
:label="$t('g.continue')"
type="secondary"
size="md"
variant="secondary"
size="lg"
data-attr="upload-model-step1-continue-button"
:disabled="!canFetchMetadata || isFetchingMetadata"
@click="emit('fetchMetadata')"
>
<template #icon>
<i
v-if="isFetchingMetadata"
class="icon-[lucide--loader-circle] animate-spin"
/>
</template>
</IconTextButton>
<IconTextButton
<i
v-if="isFetchingMetadata"
class="icon-[lucide--loader-circle] animate-spin"
/>
<span>{{ $t('g.continue') }}</span>
</Button>
<Button
v-else-if="currentStep === 2"
:label="$t('assetBrowser.upload')"
type="secondary"
size="md"
variant="secondary"
size="lg"
data-attr="upload-model-step2-confirm-button"
:disabled="!canUploadModel || isUploading"
@click="emit('upload')"
>
<template #icon>
<i
v-if="isUploading"
class="icon-[lucide--loader-circle] animate-spin"
/>
</template>
</IconTextButton>
<i v-if="isUploading" class="icon-[lucide--loader-circle] animate-spin" />
<span>{{ $t('assetBrowser.upload') }}</span>
</Button>
<Button
v-else-if="currentStep === 3 && uploadStatus === 'success'"
variant="secondary"
@@ -86,7 +77,6 @@
<script setup lang="ts">
import { ref } from 'vue'
import IconTextButton from '@/components/button/IconTextButton.vue'
import Button from '@/components/ui/button/Button.vue'
import VideoHelpDialog from '@/platform/assets/components/VideoHelpDialog.vue'