feat(ui): add the plan switcher dropdown
This commit is contained in:
33
src/components/PlanSwitcher.test.ts
Normal file
33
src/components/PlanSwitcher.test.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
// @vitest-environment happy-dom
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import PlanSwitcher from './PlanSwitcher.vue'
|
||||
|
||||
const plans = [
|
||||
{ id: 'a', name: 'Alpha' },
|
||||
{ id: 'b', name: 'Bravo' },
|
||||
]
|
||||
|
||||
describe('PlanSwitcher', () => {
|
||||
it('lists plan names and marks the active one', () => {
|
||||
const w = mount(PlanSwitcher, { props: { plans, activeId: 'b' } })
|
||||
expect(w.text()).toContain('Alpha')
|
||||
expect(w.text()).toContain('Bravo')
|
||||
expect(w.find('a.active').text()).toContain('Bravo')
|
||||
})
|
||||
|
||||
it('emits select with the clicked plan id', async () => {
|
||||
const w = mount(PlanSwitcher, { props: { plans, activeId: 'a' } })
|
||||
await w.findAll('li a')[1].trigger('click') // Bravo
|
||||
expect(w.emitted('select')?.[0]).toEqual(['b'])
|
||||
})
|
||||
|
||||
it('emits new and download (with the active id) from the trailing actions', async () => {
|
||||
const w = mount(PlanSwitcher, { props: { plans, activeId: 'a' } })
|
||||
const actions = w.findAll('li a')
|
||||
await actions[actions.length - 2].trigger('click') // New plan
|
||||
await actions[actions.length - 1].trigger('click') // Download .toml
|
||||
expect(w.emitted('new')).toBeTruthy()
|
||||
expect(w.emitted('download')?.[0]).toEqual(['a'])
|
||||
})
|
||||
})
|
||||
41
src/components/PlanSwitcher.vue
Normal file
41
src/components/PlanSwitcher.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
plans: { id: string; name: string }[]
|
||||
activeId: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
select: [id: string]
|
||||
new: []
|
||||
download: [id: string]
|
||||
}>()
|
||||
|
||||
const activeName = computed(
|
||||
() => props.plans.find((p) => p.id === props.activeId)?.name ?? 'Untitled',
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="dropdown">
|
||||
<div tabindex="0" role="button" class="btn btn-ghost btn-sm gap-1 normal-case">
|
||||
<span class="max-w-[14rem] truncate font-semibold">{{ activeName }}</span>
|
||||
<span aria-hidden="true">▾</span>
|
||||
</div>
|
||||
<ul
|
||||
tabindex="0"
|
||||
class="menu dropdown-content z-50 mt-1 w-64 rounded-box border border-base-300 bg-base-100 p-2 shadow-lg"
|
||||
>
|
||||
<li v-for="p in plans" :key="p.id">
|
||||
<a :class="{ active: p.id === activeId }" @click="emit('select', p.id)">
|
||||
<span class="truncate">{{ p.name }}</span>
|
||||
<span v-if="p.id === activeId" aria-hidden="true">✓</span>
|
||||
</a>
|
||||
</li>
|
||||
<div class="my-1 border-t border-base-200"></div>
|
||||
<li><a @click="emit('new')">+ New plan</a></li>
|
||||
<li><a @click="emit('download', activeId)">⤓ Download .toml</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user