mirror of
https://github.com/koel/koel
synced 2024-11-28 06:50:27 +00:00
feat: use dialog element for overlay component (#1594)
This commit is contained in:
parent
2dbda9fe7e
commit
bd0585e587
7 changed files with 67 additions and 74 deletions
|
@ -17,13 +17,21 @@ global.ResizeObserver = global.ResizeObserver ||
|
|||
unobserve: vi.fn()
|
||||
}))
|
||||
|
||||
window.HTMLMediaElement.prototype.load = vi.fn()
|
||||
window.HTMLMediaElement.prototype.play = vi.fn()
|
||||
window.HTMLMediaElement.prototype.pause = vi.fn()
|
||||
HTMLMediaElement.prototype.load = vi.fn()
|
||||
HTMLMediaElement.prototype.play = vi.fn()
|
||||
HTMLMediaElement.prototype.pause = vi.fn()
|
||||
|
||||
window.HTMLDialogElement.prototype.show = vi.fn()
|
||||
window.HTMLDialogElement.prototype.showModal = vi.fn()
|
||||
window.HTMLDialogElement.prototype.close = vi.fn()
|
||||
HTMLDialogElement.prototype.show = vi.fn(function mock () {
|
||||
this.open = true
|
||||
})
|
||||
|
||||
HTMLDialogElement.prototype.showModal = vi.fn(function mock () {
|
||||
this.open = true
|
||||
})
|
||||
|
||||
HTMLDialogElement.prototype.close = vi.fn(function mock () {
|
||||
this.open = false
|
||||
})
|
||||
|
||||
window.BASE_URL = 'http://test/'
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import UnitTestCase from '@/__tests__/UnitTestCase'
|
||||
import { expect, it } from 'vitest'
|
||||
import { eventBus } from '@/utils'
|
||||
import { waitFor } from '@testing-library/vue'
|
||||
import SoundBars from '@/components/ui/SoundBars.vue'
|
||||
import Overlay from './Overlay.vue'
|
||||
|
||||
|
@ -32,14 +31,18 @@ new class extends UnitTestCase {
|
|||
['info'],
|
||||
['warning'],
|
||||
['error']
|
||||
])('renders %s type', async (type) => expect((await this.renderComponent(type)).html()).toMatchSnapshot())
|
||||
])('renders %s type', async type => {
|
||||
const { getByTestId, html } = await this.renderComponent(type)
|
||||
|
||||
expect(html()).toMatchSnapshot()
|
||||
expect((getByTestId('overlay') as HTMLDialogElement).open).toBe(true)
|
||||
})
|
||||
|
||||
it('closes', async () => {
|
||||
const { queryByTestId } = await this.renderComponent()
|
||||
expect(queryByTestId('overlay')).not.toBeNull()
|
||||
const { getByTestId } = await this.renderComponent()
|
||||
|
||||
eventBus.emit('HIDE_OVERLAY')
|
||||
await waitFor(() => expect(queryByTestId('overlay')).toBeNull())
|
||||
expect((getByTestId('overlay') as HTMLDialogElement).open).toBe(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div v-if="state.showing" id="overlay" :class="state.type" class="overlay" data-testid="overlay">
|
||||
<div class="display">
|
||||
<dialog ref="el" :class="state.type" @cancel.prevent="onCancel" data-testid="overlay">
|
||||
<div class="wrapper">
|
||||
<SoundBars v-if="state.type === 'loading'"/>
|
||||
<icon v-if="state.type === 'error'" :icon="faCircleExclamation"/>
|
||||
<icon v-if="state.type === 'warning'" :icon="faWarning"/>
|
||||
|
@ -9,49 +9,51 @@
|
|||
|
||||
<span class="message" v-html="state.message"/>
|
||||
</div>
|
||||
|
||||
<button v-if="state.dismissible" class="btn-dismiss" type="button" @click.prevent="hide">Close</button>
|
||||
</div>
|
||||
</dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { faCircleCheck, faCircleExclamation, faCircleInfo, faWarning } from '@fortawesome/free-solid-svg-icons'
|
||||
import { defineAsyncComponent, reactive, ref } from 'vue'
|
||||
import { eventBus } from '@/utils'
|
||||
import { defineAsyncComponent, reactive } from 'vue'
|
||||
|
||||
const SoundBars = defineAsyncComponent(() => import('@/components/ui/SoundBars.vue'))
|
||||
|
||||
const el = ref<HTMLDialogElement>()
|
||||
|
||||
const state = reactive<OverlayState>({
|
||||
showing: false,
|
||||
dismissible: false,
|
||||
type: 'loading',
|
||||
message: ''
|
||||
})
|
||||
|
||||
const show = (options: Partial<OverlayState>) => {
|
||||
const show = (options: Partial<OverlayState> = {}) => {
|
||||
Object.assign(state, options)
|
||||
state.showing = true
|
||||
el.value?.open || el.value?.showModal()
|
||||
}
|
||||
|
||||
const hide = () => (state.showing = false)
|
||||
const hide = () => el.value?.close()
|
||||
const onCancel = () => state.dismissible && hide()
|
||||
|
||||
eventBus.on('SHOW_OVERLAY', options => show(options))
|
||||
.on('HIDE_OVERLAY', () => hide())
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#overlay {
|
||||
background-color: var(--color-bg-primary);
|
||||
flex-direction: column;
|
||||
<style lang="scss" scoped>
|
||||
dialog {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
|
||||
.display {
|
||||
&::backdrop {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
|
||||
.message {
|
||||
margin-left: 6px;
|
||||
}
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
&.error {
|
||||
|
@ -71,7 +73,7 @@ eventBus.on('SHOW_OVERLAY', options => show(options))
|
|||
}
|
||||
|
||||
&.warning {
|
||||
color: var(--color-highlight);
|
||||
color: var(--color-orange);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,61 +1,56 @@
|
|||
// Vitest Snapshot v1
|
||||
|
||||
exports[`renders error type 1`] = `
|
||||
<div id="overlay" class="error overlay" data-testid="overlay">
|
||||
<div class="display">
|
||||
<!--v-if--><br data-testid="icon" icon="[object Object]">
|
||||
<dialog class="error" data-testid="overlay" data-v-889cac1d="" open="">
|
||||
<div class="wrapper" data-v-889cac1d="">
|
||||
<!--v-if--><br data-testid="icon" icon="[object Object]" data-v-889cac1d="">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if--><span class="message">Look at me now</span>
|
||||
<!--v-if--><span class="message" data-v-889cac1d="">Look at me now</span>
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
||||
|
||||
exports[`renders info type 1`] = `
|
||||
<div id="overlay" class="info overlay" data-testid="overlay">
|
||||
<div class="display">
|
||||
<dialog class="info" data-testid="overlay" data-v-889cac1d="" open="">
|
||||
<div class="wrapper" data-v-889cac1d="">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if--><br data-testid="icon" icon="[object Object]">
|
||||
<!--v-if--><span class="message">Look at me now</span>
|
||||
<!--v-if--><br data-testid="icon" icon="[object Object]" data-v-889cac1d="">
|
||||
<!--v-if--><span class="message" data-v-889cac1d="">Look at me now</span>
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
||||
|
||||
exports[`renders loading type 1`] = `
|
||||
<div id="overlay" class="loading overlay" data-testid="overlay">
|
||||
<div class="display"><i data-v-47e95701=""><span data-v-47e95701=""></span><span data-v-47e95701=""></span><span data-v-47e95701=""></span></i>
|
||||
<dialog class="loading" data-testid="overlay" data-v-889cac1d="" open="">
|
||||
<div class="wrapper" data-v-889cac1d=""><i data-v-47e95701="" data-v-889cac1d=""><span data-v-47e95701=""></span><span data-v-47e95701=""></span><span data-v-47e95701=""></span></i>
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if--><span class="message">Look at me now</span>
|
||||
<!--v-if--><span class="message" data-v-889cac1d="">Look at me now</span>
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
||||
|
||||
exports[`renders success type 1`] = `
|
||||
<div id="overlay" class="success overlay" data-testid="overlay">
|
||||
<div class="display">
|
||||
<dialog class="success" data-testid="overlay" data-v-889cac1d="" open="">
|
||||
<div class="wrapper" data-v-889cac1d="">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if--><br data-testid="icon" icon="[object Object]"><span class="message">Look at me now</span>
|
||||
<!--v-if--><br data-testid="icon" icon="[object Object]" data-v-889cac1d=""><span class="message" data-v-889cac1d="">Look at me now</span>
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
||||
|
||||
exports[`renders warning type 1`] = `
|
||||
<div id="overlay" class="warning overlay" data-testid="overlay">
|
||||
<div class="display">
|
||||
<dialog class="warning" data-testid="overlay" data-v-889cac1d="" open="">
|
||||
<div class="wrapper" data-v-889cac1d="">
|
||||
<!--v-if-->
|
||||
<!--v-if--><br data-testid="icon" icon="[object Object]">
|
||||
<!--v-if--><br data-testid="icon" icon="[object Object]" data-v-889cac1d="">
|
||||
<!--v-if-->
|
||||
<!--v-if--><span class="message">Look at me now</span>
|
||||
<!--v-if--><span class="message" data-v-889cac1d="">Look at me now</span>
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
||||
|
|
|
@ -6,7 +6,6 @@ import Router from '@/router'
|
|||
export type ReadonlyInjectionKey<T> = InjectionKey<[Readonly<T> | DeepReadonly<T>, Closure]>
|
||||
|
||||
export const RouterKey: InjectionKey<Router> = Symbol('Router')
|
||||
export const ScreenNameKey: ReadonlyInjectionKey<ScreenName> = Symbol('ScreenName')
|
||||
|
||||
export const DialogBoxKey: InjectionKey<Ref<InstanceType<typeof DialogBox>>> = Symbol('DialogBox')
|
||||
export const MessageToasterKey: InjectionKey<Ref<InstanceType<typeof MessageToaster>>> = Symbol('MessageToaster')
|
||||
|
|
1
resources/assets/js/types.d.ts
vendored
1
resources/assets/js/types.d.ts
vendored
|
@ -267,7 +267,6 @@ interface EqualizerBandElement extends HTMLElement {
|
|||
}
|
||||
|
||||
type OverlayState = {
|
||||
showing: boolean
|
||||
dismissible: boolean
|
||||
type: 'loading' | 'success' | 'info' | 'warning' | 'error'
|
||||
message: string
|
||||
|
|
|
@ -185,19 +185,6 @@ label {
|
|||
height: 32px;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(0, 0, 0, .7);
|
||||
|
||||
@include vertical-center();
|
||||
}
|
||||
|
||||
.font-size- {
|
||||
&0 {
|
||||
font-size: 0;
|
||||
|
|
Loading…
Reference in a new issue