Apply glassmorphism design system across all UI surfaces #23

Merged
nitrix merged 11 commits from glassmorphism-event-cards into master 2026-03-09 19:11:53 +01:00
3 changed files with 35 additions and 9 deletions
Showing only changes of commit 5dd7cb3fb8 - Show all commits

View File

@@ -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 {

View File

@@ -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)
}) })

View File

@@ -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