diff --git a/src/components/queue/job/QueueJobItem.vue b/src/components/queue/job/QueueJobItem.vue
index 7e71840bc..b1809dac2 100644
--- a/src/components/queue/job/QueueJobItem.vue
+++ b/src/components/queue/job/QueueJobItem.vue
@@ -50,20 +50,22 @@
@@ -201,6 +203,7 @@ import { useI18n } from 'vue-i18n'
import JobDetailsPopover from '@/components/queue/job/JobDetailsPopover.vue'
import QueueAssetPreview from '@/components/queue/job/QueueAssetPreview.vue'
import Button from '@/components/ui/button/Button.vue'
+import { useProgressBarBackground } from '@/composables/useProgressBarBackground'
import { buildTooltipConfig } from '@/composables/useTooltipConfig'
import type { JobState } from '@/types/queue'
import { iconForJobState } from '@/utils/queueDisplay'
@@ -245,6 +248,14 @@ const emit = defineEmits<{
}>()
const { t } = useI18n()
+const {
+ progressBarContainerClass,
+ progressBarPrimaryClass,
+ progressBarSecondaryClass,
+ hasProgressPercent,
+ hasAnyProgressPercent,
+ progressPercentStyle
+} = useProgressBarBackground()
const cancelTooltipConfig = computed(() => buildTooltipConfig(t('g.cancel')))
const deleteTooltipConfig = computed(() => buildTooltipConfig(t('g.delete')))
diff --git a/src/components/sidebar/tabs/AssetsSidebarListView.vue b/src/components/sidebar/tabs/AssetsSidebarListView.vue
new file mode 100644
index 000000000..f750661ba
--- /dev/null
+++ b/src/components/sidebar/tabs/AssetsSidebarListView.vue
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+ {{ t('sideToolbar.generatedAssetsHeader') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/sidebar/tabs/AssetsSidebarTab.vue b/src/components/sidebar/tabs/AssetsSidebarTab.vue
index 032645b4c..7da25bb8e 100644
--- a/src/components/sidebar/tabs/AssetsSidebarTab.vue
+++ b/src/components/sidebar/tabs/AssetsSidebarTab.vue
@@ -79,10 +79,10 @@
-
+
-
+
+
= {
+ title: 'Platform/Assets/AssetsListItem',
+ component: AssetsListItem,
+ parameters: {
+ layout: 'centered'
+ },
+ decorators: [
+ () => ({
+ template: '
'
+ })
+ ]
+}
+
+export default meta
+type Story = StoryObj
+type AssetsListItemProps = InstanceType['$props']
+
+function renderActiveJob(args: AssetsListItemProps) {
+ return {
+ components: { Button, AssetsListItem },
+ setup() {
+ return { args }
+ },
+ template: `
+
+
+
+ Total:
+ 30%
+
+
+
+
+ CLIP Text Encode:
+ 70%
+
+
+
+
+
+
+ `
+ }
+}
+
+function renderGeneratedAsset(args: AssetsListItemProps) {
+ return {
+ components: { AssetsListItem },
+ setup() {
+ return { args }
+ },
+ template: `
+
+
+
+ 1m 56s
+ 512x512
+
+
+
+ `
+ }
+}
+
+export const ActiveJob: Story = {
+ args: {
+ previewUrl: '/assets/images/comfy-logo-single.svg',
+ previewAlt: 'Job preview',
+ progressTotalPercent: 30,
+ progressCurrentPercent: 70
+ },
+ render: renderActiveJob
+}
+
+export const FailedJob: Story = {
+ args: {
+ iconName: 'icon-[lucide--circle-alert]',
+ iconClass: 'text-destructive-background',
+ iconWrapperClass: 'bg-modal-card-placeholder-background',
+ primaryText: 'Failed',
+ secondaryText: '8:59:30pm'
+ }
+}
+
+export const GeneratedAsset: Story = {
+ args: {
+ previewUrl: '/assets/images/comfy-logo-single.svg',
+ previewAlt: 'image03.png',
+ primaryText: 'image03.png'
+ },
+ render: renderGeneratedAsset
+}
diff --git a/src/platform/assets/components/AssetsListItem.vue b/src/platform/assets/components/AssetsListItem.vue
new file mode 100644
index 000000000..3f04d372f
--- /dev/null
+++ b/src/platform/assets/components/AssetsListItem.vue
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ primaryText }}
+
+
+ {{ secondaryText }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/platform/assets/utils/mediaIconUtil.ts b/src/platform/assets/utils/mediaIconUtil.ts
new file mode 100644
index 000000000..d698fa610
--- /dev/null
+++ b/src/platform/assets/utils/mediaIconUtil.ts
@@ -0,0 +1,14 @@
+import type { MediaKind } from '@/platform/assets/schemas/mediaAssetSchema'
+
+export function iconForMediaType(mediaType: MediaKind): string {
+ switch (mediaType) {
+ case 'video':
+ return 'icon-[lucide--video]'
+ case 'audio':
+ return 'icon-[lucide--music]'
+ case '3D':
+ return 'icon-[lucide--box]'
+ default:
+ return 'icon-[lucide--image]'
+ }
+}