Apply glassmorphism design system across all UI surfaces #23
@@ -8,9 +8,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- CTA state: no RSVP yet -->
|
<!-- CTA state: no RSVP yet -->
|
||||||
<button v-else class="btn-primary rsvp-bar__cta" type="button" @click="$emit('open')">
|
<div v-else class="rsvp-bar__cta glow-border glow-border--animated">
|
||||||
I'm attending
|
<button class="rsvp-bar__cta-inner glass-inner" type="button" @click="$emit('open')">
|
||||||
</button>
|
I'm attending
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -45,6 +47,30 @@ defineEmits<{
|
|||||||
|
|
||||||
.rsvp-bar__cta {
|
.rsvp-bar__cta {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
border-radius: var(--radius-button);
|
||||||
|
transition: transform 0.1s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rsvp-bar__cta:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rsvp-bar__cta:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rsvp-bar__cta-inner {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: var(--spacing-md) var(--spacing-lg);
|
||||||
|
border-radius: calc(var(--radius-button) - 2px);
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-text-on-gradient);
|
||||||
|
text-align: center;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rsvp-bar__status {
|
.rsvp-bar__status {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ describe('RsvpBar', () => {
|
|||||||
it('renders CTA button when hasRsvp is false', () => {
|
it('renders CTA button when hasRsvp is false', () => {
|
||||||
const wrapper = mount(RsvpBar)
|
const wrapper = mount(RsvpBar)
|
||||||
expect(wrapper.find('.rsvp-bar__cta').exists()).toBe(true)
|
expect(wrapper.find('.rsvp-bar__cta').exists()).toBe(true)
|
||||||
expect(wrapper.find('.rsvp-bar__cta').text()).toBe("I'm attending")
|
expect(wrapper.find('.rsvp-bar__cta-inner').text()).toBe("I'm attending")
|
||||||
expect(wrapper.find('.rsvp-bar__status').exists()).toBe(false)
|
expect(wrapper.find('.rsvp-bar__status').exists()).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ describe('RsvpBar', () => {
|
|||||||
|
|
||||||
it('emits open when CTA button is clicked', async () => {
|
it('emits open when CTA button is clicked', async () => {
|
||||||
const wrapper = mount(RsvpBar)
|
const wrapper = mount(RsvpBar)
|
||||||
await wrapper.find('.rsvp-bar__cta').trigger('click')
|
await wrapper.find('.rsvp-bar__cta-inner').trigger('click')
|
||||||
expect(wrapper.emitted('open')).toHaveLength(1)
|
expect(wrapper.emitted('open')).toHaveLength(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ describe('EventDetailView', () => {
|
|||||||
|
|
||||||
expect(document.body.querySelector('[role="dialog"]')).toBeNull()
|
expect(document.body.querySelector('[role="dialog"]')).toBeNull()
|
||||||
|
|
||||||
await wrapper.find('.rsvp-bar__cta').trigger('click')
|
await wrapper.find('.rsvp-bar__cta-inner').trigger('click')
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
expect(document.body.querySelector('[role="dialog"]')).not.toBeNull()
|
expect(document.body.querySelector('[role="dialog"]')).not.toBeNull()
|
||||||
@@ -275,7 +275,7 @@ describe('EventDetailView', () => {
|
|||||||
const wrapper = await mountWithToken()
|
const wrapper = await mountWithToken()
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
await wrapper.find('.rsvp-bar__cta').trigger('click')
|
await wrapper.find('.rsvp-bar__cta-inner').trigger('click')
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
// Form is inside Teleport — find via document.body
|
// Form is inside Teleport — find via document.body
|
||||||
@@ -300,7 +300,7 @@ describe('EventDetailView', () => {
|
|||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
// Open sheet
|
// Open sheet
|
||||||
await wrapper.find('.rsvp-bar__cta').trigger('click')
|
await wrapper.find('.rsvp-bar__cta-inner').trigger('click')
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
// Fill name via Teleported input
|
// Fill name via Teleported input
|
||||||
@@ -386,7 +386,7 @@ describe('EventDetailView', () => {
|
|||||||
const wrapper = await mountWithToken()
|
const wrapper = await mountWithToken()
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
await wrapper.find('.rsvp-bar__cta').trigger('click')
|
await wrapper.find('.rsvp-bar__cta-inner').trigger('click')
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
const input = document.body.querySelector('#rsvp-name')! as HTMLInputElement
|
const input = document.body.querySelector('#rsvp-name')! as HTMLInputElement
|
||||||
|
|||||||
Reference in New Issue
Block a user