feat: add Logo C fill and Comfy wave loading indicator components (#9433)

## Summary

Add SVG-based brand loading indicators (LogoCFillLoader,
LogoComfyWaveLoader) and use the wave loader as the app loading screen.

## Changes

- **What**: New `LogoCFillLoader` (bottom-to-top fill, plays once) and
`LogoComfyWaveLoader` (wave water-fill animation) components with
`size`, `color`, `bordered`, and `disableAnimation` props. Move all
loaders from `components/common/` to `components/loader/`. Use
`LogoComfyWaveLoader` in `App.vue` and `WorkspaceAuthGate.vue`. Render
loader above BlockUI overlay (z-1200) to prevent dim wash-out.
- **Dependencies**: None

## Review Focus

- SVG mask-based animation approach using `currentColor` for flexible
theming
- z-index layering: loader at z-1200 renders above PrimeVue BlockUI's
z-1100 modal overlay
- `disableAnimation` prop used in WorkspaceAuthGate to show static logo
outline during auth loading

## Screenshots (if applicable)

[loading_record.webm](https://github.com/user-attachments/assets/b34f7296-9904-4a42-9273-a7d5fda49d15)

Storybook stories added for both components under `Components/Loader/`.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9433-feat-add-Logo-C-fill-and-Comfy-wave-loading-indicator-components-31a6d73d3650811cacfdcf867b1f835f)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Jin Yi
2026-03-06 17:32:20 +09:00
committed by GitHub
parent e2cb3560cc
commit 96fd25de5c
16 changed files with 421 additions and 18 deletions

View File

@@ -1,50 +0,0 @@
import type { Meta, StoryObj } from '@storybook/vue3-vite'
import Loader from './Loader.vue'
const meta: Meta<typeof Loader> = {
title: 'Components/Common/Loader',
component: Loader,
tags: ['autodocs'],
parameters: {
layout: 'centered'
},
argTypes: {
size: {
control: 'select',
options: ['sm', 'md', 'lg'],
description: 'Spinner size: sm (16px), md (32px), lg (48px)'
}
}
}
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {}
export const Small: Story = {
args: { size: 'sm' }
}
export const Medium: Story = {
args: { size: 'md' }
}
export const Large: Story = {
args: { size: 'lg' }
}
export const CustomColor: Story = {
render: (args) => ({
components: { Loader },
setup() {
return { args }
},
template:
'<div class="flex gap-4 items-center"><Loader size="lg" class="text-white" /><Loader size="md" class="text-muted-foreground" /><Loader size="sm" class="text-base-foreground" /></div>'
}),
parameters: {
backgrounds: { default: 'dark' }
}
}

View File

@@ -1,29 +0,0 @@
<template>
<span role="status" class="inline-flex">
<i
aria-hidden="true"
:class="cn('icon-[lucide--loader-circle] animate-spin', sizeClass)"
/>
<span class="sr-only">{{ t('g.loading') }}</span>
</span>
</template>
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import { cn } from '@/utils/tailwindUtil'
const { size } = defineProps<{
size?: 'sm' | 'md' | 'lg'
}>()
const { t } = useI18n()
const sizeMap = {
sm: 'size-4',
md: 'size-8',
lg: 'size-12'
} as const
const sizeClass = size ? sizeMap[size] : ''
</script>