mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 03:01:54 +00:00
style: update Vue node designs to use semantic tokens (#6304)
## Summary Use semantic tokens instead of colors ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6304-style-update-Vue-node-designs-to-use-semantic-tokens-2986d73d365081f69acce7793a218699) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -107,10 +107,14 @@ describe('WidgetSelectButton Button Selection', () => {
|
|||||||
const selectedButton = buttons[1] // 'banana'
|
const selectedButton = buttons[1] // 'banana'
|
||||||
const unselectedButton = buttons[0] // 'apple'
|
const unselectedButton = buttons[0] // 'apple'
|
||||||
|
|
||||||
expect(selectedButton.classes()).toContain('bg-white')
|
expect(selectedButton.classes()).toContain(
|
||||||
expect(selectedButton.classes()).toContain('text-neutral-900')
|
'bg-interface-menu-component-surface-selected'
|
||||||
expect(unselectedButton.classes()).not.toContain('bg-white')
|
)
|
||||||
expect(unselectedButton.classes()).not.toContain('text-neutral-900')
|
expect(selectedButton.classes()).toContain('text-primary')
|
||||||
|
expect(unselectedButton.classes()).not.toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
|
expect(unselectedButton.classes()).toContain('text-secondary')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles no selection gracefully', () => {
|
it('handles no selection gracefully', () => {
|
||||||
@@ -120,8 +124,10 @@ describe('WidgetSelectButton Button Selection', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
buttons.forEach((button) => {
|
buttons.forEach((button) => {
|
||||||
expect(button.classes()).not.toContain('bg-white')
|
expect(button.classes()).not.toContain(
|
||||||
expect(button.classes()).not.toContain('text-neutral-900')
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
|
expect(button.classes()).toContain('text-secondary')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -134,13 +140,19 @@ describe('WidgetSelectButton Button Selection', () => {
|
|||||||
|
|
||||||
// Initially 'first' is selected
|
// Initially 'first' is selected
|
||||||
let buttons = wrapper.findAll('button')
|
let buttons = wrapper.findAll('button')
|
||||||
expect(buttons[0].classes()).toContain('bg-white')
|
expect(buttons[0].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
|
|
||||||
// Update to 'second'
|
// Update to 'second'
|
||||||
await wrapper.setProps({ modelValue: 'second' })
|
await wrapper.setProps({ modelValue: 'second' })
|
||||||
buttons = wrapper.findAll('button')
|
buttons = wrapper.findAll('button')
|
||||||
expect(buttons[0].classes()).not.toContain('bg-white')
|
expect(buttons[0].classes()).not.toContain(
|
||||||
expect(buttons[1].classes()).toContain('bg-white')
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
|
expect(buttons[1].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -222,7 +234,9 @@ describe('WidgetSelectButton Button Selection', () => {
|
|||||||
expect(buttons[2].text()).toBe('3')
|
expect(buttons[2].text()).toBe('3')
|
||||||
|
|
||||||
// The selected button should be the one with '2'
|
// The selected button should be the one with '2'
|
||||||
expect(buttons[1].classes()).toContain('bg-white')
|
expect(buttons[1].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles object options with label and value', () => {
|
it('handles object options with label and value', () => {
|
||||||
@@ -240,7 +254,9 @@ describe('WidgetSelectButton Button Selection', () => {
|
|||||||
expect(buttons[2].text()).toBe('Third Option')
|
expect(buttons[2].text()).toBe('Third Option')
|
||||||
|
|
||||||
// 'second' should be selected
|
// 'second' should be selected
|
||||||
expect(buttons[1].classes()).toContain('bg-white')
|
expect(buttons[1].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('emits correct values for object options', async () => {
|
it('emits correct values for object options', async () => {
|
||||||
@@ -277,7 +293,9 @@ describe('WidgetSelectButton Button Selection', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons).toHaveLength(4)
|
expect(buttons).toHaveLength(4)
|
||||||
expect(buttons[0].classes()).toContain('bg-white') // Empty string is selected
|
expect(buttons[0].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
) // Empty string is selected
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles null/undefined in options', () => {
|
it('handles null/undefined in options', () => {
|
||||||
@@ -292,7 +310,9 @@ describe('WidgetSelectButton Button Selection', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons).toHaveLength(4)
|
expect(buttons).toHaveLength(4)
|
||||||
expect(buttons[0].classes()).toContain('bg-white')
|
expect(buttons[0].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles very long option text', () => {
|
it('handles very long option text', () => {
|
||||||
@@ -313,7 +333,9 @@ describe('WidgetSelectButton Button Selection', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons).toHaveLength(20)
|
expect(buttons).toHaveLength(20)
|
||||||
expect(buttons[4].classes()).toContain('bg-white') // option5 is at index 4
|
expect(buttons[4].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
) // option5 is at index 4
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles duplicate options', () => {
|
it('handles duplicate options', () => {
|
||||||
@@ -324,8 +346,12 @@ describe('WidgetSelectButton Button Selection', () => {
|
|||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons).toHaveLength(4)
|
expect(buttons).toHaveLength(4)
|
||||||
// Both 'duplicate' buttons should be highlighted (due to value matching)
|
// Both 'duplicate' buttons should be highlighted (due to value matching)
|
||||||
expect(buttons[0].classes()).toContain('bg-white')
|
expect(buttons[0].classes()).toContain(
|
||||||
expect(buttons[2].classes()).toContain('bg-white')
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
|
expect(buttons[2].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -354,7 +380,9 @@ describe('WidgetSelectButton Button Selection', () => {
|
|||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
const unselectedButton = buttons[1] // 'option2'
|
const unselectedButton = buttons[1] // 'option2'
|
||||||
|
|
||||||
expect(unselectedButton.classes()).toContain('hover:bg-zinc-200/50')
|
expect(unselectedButton.classes()).toContain(
|
||||||
|
'hover:bg-interface-menu-component-surface-hovered'
|
||||||
|
)
|
||||||
expect(unselectedButton.classes()).toContain('cursor-pointer')
|
expect(unselectedButton.classes()).toContain('cursor-pointer')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -24,17 +24,14 @@
|
|||||||
role="button"
|
role="button"
|
||||||
:tabindex="0"
|
:tabindex="0"
|
||||||
aria-label="Play/Pause"
|
aria-label="Play/Pause"
|
||||||
class="flex size-6 cursor-pointer items-center justify-center rounded hover:bg-black/10 dark-theme:hover:bg-white/10"
|
class="flex size-6 cursor-pointer items-center justify-center rounded hover:bg-interface-menu-component-surface-hovered"
|
||||||
@click="togglePlayPause"
|
@click="togglePlayPause"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
v-if="!isPlaying"
|
v-if="!isPlaying"
|
||||||
class="icon-[lucide--play] size-4 text-smoke-600 dark-theme:text-smoke-800"
|
class="text-secondary icon-[lucide--play] size-4"
|
||||||
/>
|
|
||||||
<i
|
|
||||||
v-else
|
|
||||||
class="icon-[lucide--pause] size-4 text-smoke-600 dark-theme:text-smoke-800"
|
|
||||||
/>
|
/>
|
||||||
|
<i v-else class="text-secondary icon-[lucide--pause] size-4" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Time Display -->
|
<!-- Time Display -->
|
||||||
@@ -44,11 +41,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Progress Bar -->
|
<!-- Progress Bar -->
|
||||||
<div
|
<div class="relative h-0.5 flex-1 rounded-full bg-interface-stroke">
|
||||||
class="relative h-0.5 flex-1 rounded-full bg-smoke-300 dark-theme:bg-ash-800"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="absolute top-0 left-0 h-full rounded-full bg-smoke-600 transition-all dark-theme:bg-white/50"
|
class="absolute top-0 left-0 h-full rounded-full bg-button-icon transition-all"
|
||||||
:style="{ width: `${progressPercentage}%` }"
|
:style="{ width: `${progressPercentage}%` }"
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
@@ -70,21 +65,18 @@
|
|||||||
role="button"
|
role="button"
|
||||||
:tabindex="0"
|
:tabindex="0"
|
||||||
aria-label="Volume"
|
aria-label="Volume"
|
||||||
class="flex size-6 cursor-pointer items-center justify-center rounded hover:bg-black/10 dark-theme:hover:bg-white/10"
|
class="flex size-6 cursor-pointer items-center justify-center rounded hover:bg-interface-menu-component-surface-hovered"
|
||||||
@click="toggleMute"
|
@click="toggleMute"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
v-if="showVolumeTwo"
|
v-if="showVolumeTwo"
|
||||||
class="icon-[lucide--volume-2] size-4 text-smoke-600 dark-theme:text-smoke-800"
|
class="text-secondary icon-[lucide--volume-2] size-4"
|
||||||
/>
|
/>
|
||||||
<i
|
<i
|
||||||
v-else-if="showVolumeOne"
|
v-else-if="showVolumeOne"
|
||||||
class="icon-[lucide--volume-1] size-4 text-smoke-600 dark-theme:text-smoke-800"
|
class="text-secondary icon-[lucide--volume-1] size-4"
|
||||||
/>
|
|
||||||
<i
|
|
||||||
v-else
|
|
||||||
class="icon-[lucide--volume-x] size-4 text-smoke-600 dark-theme:text-smoke-800"
|
|
||||||
/>
|
/>
|
||||||
|
<i v-else class="text-secondary icon-[lucide--volume-x] size-4" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Options Button -->
|
<!-- Options Button -->
|
||||||
@@ -94,12 +86,10 @@
|
|||||||
role="button"
|
role="button"
|
||||||
:tabindex="0"
|
:tabindex="0"
|
||||||
aria-label="More Options"
|
aria-label="More Options"
|
||||||
class="flex size-6 cursor-pointer items-center justify-center rounded hover:bg-black/10 dark-theme:hover:bg-white/10"
|
class="flex size-6 cursor-pointer items-center justify-center rounded hover:bg-interface-menu-component-surface-hovered"
|
||||||
@click="toggleOptionsMenu"
|
@click="toggleOptionsMenu"
|
||||||
>
|
>
|
||||||
<i
|
<i class="text-secondary icon-[lucide--more-vertical] size-4" />
|
||||||
class="icon-[lucide--more-vertical] size-4 text-smoke-600 dark-theme:text-smoke-800"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -124,10 +124,16 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
const wrapper = mountComponent('option2', options)
|
const wrapper = mountComponent('option2', options)
|
||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons[1].classes()).toContain('bg-white')
|
expect(buttons[1].classes()).toContain(
|
||||||
expect(buttons[1].classes()).toContain('text-neutral-900')
|
'bg-interface-menu-component-surface-selected'
|
||||||
expect(buttons[0].classes()).not.toContain('bg-white')
|
)
|
||||||
expect(buttons[2].classes()).not.toContain('bg-white')
|
expect(buttons[1].classes()).toContain('text-primary')
|
||||||
|
expect(buttons[0].classes()).not.toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
|
expect(buttons[2].classes()).not.toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -159,8 +165,10 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
const wrapper = mountComponent('200', options)
|
const wrapper = mountComponent('200', options)
|
||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons[1].classes()).toContain('bg-white')
|
expect(buttons[1].classes()).toContain(
|
||||||
expect(buttons[1].classes()).toContain('text-neutral-900')
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
|
expect(buttons[1].classes()).toContain('text-primary')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -201,9 +209,15 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
const wrapper = mountComponent('md', options)
|
const wrapper = mountComponent('md', options)
|
||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons[1].classes()).toContain('bg-white') // Medium
|
expect(buttons[1].classes()).toContain(
|
||||||
expect(buttons[0].classes()).not.toContain('bg-white')
|
'bg-interface-menu-component-surface-selected'
|
||||||
expect(buttons[2].classes()).not.toContain('bg-white')
|
) // Medium
|
||||||
|
expect(buttons[0].classes()).not.toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
|
expect(buttons[2].classes()).not.toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles objects without value field', () => {
|
it('handles objects without value field', () => {
|
||||||
@@ -216,7 +230,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons[0].text()).toBe('First')
|
expect(buttons[0].text()).toBe('First')
|
||||||
expect(buttons[1].text()).toBe('Second')
|
expect(buttons[1].text()).toBe('Second')
|
||||||
expect(buttons[0].classes()).toContain('bg-white')
|
expect(buttons[0].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles objects without label field', () => {
|
it('handles objects without label field', () => {
|
||||||
@@ -253,8 +269,12 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
const wrapper = mountComponent('first_id', options, { optionValue: 'id' })
|
const wrapper = mountComponent('first_id', options, { optionValue: 'id' })
|
||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons[0].classes()).toContain('bg-white')
|
expect(buttons[0].classes()).toContain(
|
||||||
expect(buttons[1].classes()).not.toContain('bg-white')
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
|
expect(buttons[1].classes()).not.toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('emits custom optionValue when clicked', async () => {
|
it('emits custom optionValue when clicked', async () => {
|
||||||
@@ -301,7 +321,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
buttons.forEach((button) => {
|
buttons.forEach((button) => {
|
||||||
expect(button.classes()).not.toContain('hover:bg-zinc-200/50')
|
expect(button.classes()).not.toContain(
|
||||||
|
'hover:bg-interface-menu-component-surface-hovered'
|
||||||
|
)
|
||||||
expect(button.classes()).not.toContain('cursor-pointer')
|
expect(button.classes()).not.toContain('cursor-pointer')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -311,7 +333,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
const wrapper = mountComponent('option1', options, { disabled: true })
|
const wrapper = mountComponent('option1', options, { disabled: true })
|
||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons[0].classes()).not.toContain('bg-white') // Selected styling disabled
|
expect(buttons[0].classes()).not.toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
) // Selected styling disabled
|
||||||
expect(buttons[0].classes()).toContain('opacity-50')
|
expect(buttons[0].classes()).toContain('opacity-50')
|
||||||
expect(buttons[0].classes()).toContain('text-secondary')
|
expect(buttons[0].classes()).toContain('text-secondary')
|
||||||
})
|
})
|
||||||
@@ -324,7 +348,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
buttons.forEach((button) => {
|
buttons.forEach((button) => {
|
||||||
expect(button.classes()).not.toContain('bg-white')
|
expect(button.classes()).not.toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -334,7 +360,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
buttons.forEach((button) => {
|
buttons.forEach((button) => {
|
||||||
expect(button.classes()).not.toContain('bg-white')
|
expect(button.classes()).not.toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -343,8 +371,12 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
const wrapper = mountComponent('', options)
|
const wrapper = mountComponent('', options)
|
||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons[0].classes()).toContain('bg-white') // Empty string is selected
|
expect(buttons[0].classes()).toContain(
|
||||||
expect(buttons[1].classes()).not.toContain('bg-white')
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
) // Empty string is selected
|
||||||
|
expect(buttons[1].classes()).not.toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('compares values as strings', () => {
|
it('compares values as strings', () => {
|
||||||
@@ -352,7 +384,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
const wrapper = mountComponent('1', options)
|
const wrapper = mountComponent('1', options)
|
||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons[0].classes()).toContain('bg-white') // '1' matches number 1 as string
|
expect(buttons[0].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
) // '1' matches number 1 as string
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -362,8 +396,10 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
const wrapper = mountComponent('option1', options)
|
const wrapper = mountComponent('option1', options)
|
||||||
|
|
||||||
const selectedButton = wrapper.findAll('button')[0]
|
const selectedButton = wrapper.findAll('button')[0]
|
||||||
expect(selectedButton.classes()).toContain('bg-white')
|
expect(selectedButton.classes()).toContain(
|
||||||
expect(selectedButton.classes()).toContain('text-neutral-900')
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
|
expect(selectedButton.classes()).toContain('text-primary')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('applies unselected styling to inactive options', () => {
|
it('applies unselected styling to inactive options', () => {
|
||||||
@@ -380,7 +416,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
const wrapper = mountComponent('option1', options, { disabled: false })
|
const wrapper = mountComponent('option1', options, { disabled: false })
|
||||||
|
|
||||||
const unselectedButton = wrapper.findAll('button')[1]
|
const unselectedButton = wrapper.findAll('button')[1]
|
||||||
expect(unselectedButton.classes()).toContain('hover:bg-zinc-200/50')
|
expect(unselectedButton.classes()).toContain(
|
||||||
|
'hover:bg-interface-menu-component-surface-hovered'
|
||||||
|
)
|
||||||
expect(unselectedButton.classes()).toContain('cursor-pointer')
|
expect(unselectedButton.classes()).toContain('cursor-pointer')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -403,7 +441,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons[0].text()).toBe('@#$%^&*()')
|
expect(buttons[0].text()).toBe('@#$%^&*()')
|
||||||
expect(buttons[0].classes()).toContain('bg-white')
|
expect(buttons[0].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles unicode characters in options', () => {
|
it('handles unicode characters in options', () => {
|
||||||
@@ -412,7 +452,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons[0].text()).toBe('🎨 Art')
|
expect(buttons[0].text()).toBe('🎨 Art')
|
||||||
expect(buttons[0].classes()).toContain('bg-white')
|
expect(buttons[0].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles duplicate option values', () => {
|
it('handles duplicate option values', () => {
|
||||||
@@ -420,9 +462,15 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
const wrapper = mountComponent('duplicate', duplicateOptions)
|
const wrapper = mountComponent('duplicate', duplicateOptions)
|
||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons[0].classes()).toContain('bg-white')
|
expect(buttons[0].classes()).toContain(
|
||||||
expect(buttons[2].classes()).toContain('bg-white') // Both duplicates selected
|
'bg-interface-menu-component-surface-selected'
|
||||||
expect(buttons[1].classes()).not.toContain('bg-white')
|
)
|
||||||
|
expect(buttons[2].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
) // Both duplicates selected
|
||||||
|
expect(buttons[1].classes()).not.toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles mixed type options safely', () => {
|
it('handles mixed type options safely', () => {
|
||||||
@@ -436,7 +484,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons).toHaveLength(4)
|
expect(buttons).toHaveLength(4)
|
||||||
expect(buttons[1].classes()).toContain('bg-white') // Number 123 as string
|
expect(buttons[1].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
) // Number 123 as string
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles objects with missing properties gracefully', () => {
|
it('handles objects with missing properties gracefully', () => {
|
||||||
@@ -450,7 +500,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons).toHaveLength(4)
|
expect(buttons).toHaveLength(4)
|
||||||
expect(buttons[2].classes()).toContain('bg-white')
|
expect(buttons[2].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles large number of options', () => {
|
it('handles large number of options', () => {
|
||||||
@@ -462,7 +514,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons).toHaveLength(50)
|
expect(buttons).toHaveLength(50)
|
||||||
expect(buttons[24].classes()).toContain('bg-white') // Option 25 at index 24
|
expect(buttons[24].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
) // Option 25 at index 24
|
||||||
})
|
})
|
||||||
|
|
||||||
it('fallback to index when all object properties are missing', () => {
|
it('fallback to index when all object properties are missing', () => {
|
||||||
@@ -474,7 +528,9 @@ describe('FormSelectButton Core Component', () => {
|
|||||||
|
|
||||||
const buttons = wrapper.findAll('button')
|
const buttons = wrapper.findAll('button')
|
||||||
expect(buttons).toHaveLength(2)
|
expect(buttons).toHaveLength(2)
|
||||||
expect(buttons[0].classes()).toContain('bg-white') // Falls back to index 0
|
expect(buttons[0].classes()).toContain(
|
||||||
|
'bg-interface-menu-component-surface-selected'
|
||||||
|
) // Falls back to index 0
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,14 @@
|
|||||||
'bg-transparent border-none',
|
'bg-transparent border-none',
|
||||||
'text-center text-xs font-normal',
|
'text-center text-xs font-normal',
|
||||||
{
|
{
|
||||||
'bg-white': isSelected(option) && !disabled,
|
'bg-interface-menu-component-surface-selected':
|
||||||
'hover:bg-zinc-200/50': !isSelected(option) && !disabled,
|
isSelected(option) && !disabled,
|
||||||
|
'hover:bg-interface-menu-component-surface-hovered':
|
||||||
|
!isSelected(option) && !disabled,
|
||||||
'opacity-50 cursor-not-allowed': disabled,
|
'opacity-50 cursor-not-allowed': disabled,
|
||||||
'cursor-pointer': !disabled
|
'cursor-pointer': !disabled
|
||||||
},
|
},
|
||||||
isSelected(option) && !disabled
|
isSelected(option) && !disabled ? 'text-primary' : 'text-secondary'
|
||||||
? 'text-neutral-900'
|
|
||||||
: 'text-secondary'
|
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const filterSelected = defineModel<OptionId>('filterSelected')
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mb-4 flex gap-1 px-4 text-zinc-400">
|
<div class="text-secondary mb-4 flex gap-1 px-4">
|
||||||
<div
|
<div
|
||||||
v-for="option in filterOptions"
|
v-for="option in filterOptions"
|
||||||
:key="option.id"
|
:key="option.id"
|
||||||
@@ -19,10 +19,10 @@ const filterSelected = defineModel<OptionId>('filterSelected')
|
|||||||
cn(
|
cn(
|
||||||
'px-4 py-2 rounded-md inline-flex justify-center items-center cursor-pointer select-none',
|
'px-4 py-2 rounded-md inline-flex justify-center items-center cursor-pointer select-none',
|
||||||
'transition-all duration-150',
|
'transition-all duration-150',
|
||||||
'hover:text-base-foreground hover:bg-zinc-500/10',
|
'hover:text-base-foreground hover:bg-interface-menu-component-surface-hovered',
|
||||||
'active:scale-95',
|
'active:scale-95',
|
||||||
filterSelected === option.id
|
filterSelected === option.id
|
||||||
? '!bg-zinc-500/20 text-base-foreground'
|
? '!bg-interface-menu-component-surface-selected text-base-foreground'
|
||||||
: 'bg-transparent'
|
: 'bg-transparent'
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ function handleVideoLoad(event: Event) {
|
|||||||
'transition-all duration-150',
|
'transition-all duration-150',
|
||||||
{
|
{
|
||||||
'flex-col text-center': layout === 'grid',
|
'flex-col text-center': layout === 'grid',
|
||||||
'flex-row text-left max-h-16 bg-zinc-500/20 rounded-lg hover:scale-102 active:scale-98':
|
'flex-row text-left max-h-16 bg-interface-menu-component-surface-hovered rounded-lg hover:scale-102 active:scale-98':
|
||||||
layout === 'list',
|
layout === 'list',
|
||||||
'flex-row text-left hover:bg-zinc-500/20 rounded-lg':
|
'flex-row text-left hover:bg-interface-menu-component-surface-hovered rounded-lg':
|
||||||
layout === 'list-small',
|
layout === 'list-small',
|
||||||
// selection
|
// selection
|
||||||
'ring-2 ring-blue-500': layout === 'list' && selected
|
'ring-2 ring-blue-500': layout === 'list' && selected
|
||||||
@@ -78,7 +78,7 @@ function handleVideoLoad(event: Event) {
|
|||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'relative',
|
'relative',
|
||||||
'w-full aspect-square overflow-hidden outline-1 outline-offset-[-1px] outline-zinc-300/10',
|
'w-full aspect-square overflow-hidden outline-1 outline-offset-[-1px] outline-interface-stroke',
|
||||||
'transition-all duration-150',
|
'transition-all duration-150',
|
||||||
{
|
{
|
||||||
'min-w-16 max-w-16 rounded-l-lg': layout === 'list',
|
'min-w-16 max-w-16 rounded-l-lg': layout === 'list',
|
||||||
@@ -144,7 +144,7 @@ function handleVideoLoad(event: Event) {
|
|||||||
{{ label ?? name }}
|
{{ label ?? name }}
|
||||||
</span>
|
</span>
|
||||||
<!-- Meta Data -->
|
<!-- Meta Data -->
|
||||||
<span class="block text-xs text-slate-400">{{
|
<span class="text-secondary block text-xs">{{
|
||||||
metadata || actualDimensions
|
metadata || actualDimensions
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user