mirror of
https://github.com/koel/koel
synced 2024-11-10 06:34:14 +00:00
feat: turn overlay functionalities into composable (#1597)
This commit is contained in:
parent
34945a507c
commit
9c776cb3b5
20 changed files with 93 additions and 146 deletions
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<Overlay/>
|
||||
<Overlay ref="overlay"/>
|
||||
<DialogBox ref="dialog"/>
|
||||
<MessageToaster ref="toaster"/>
|
||||
<GlobalEventListeners/>
|
||||
|
@ -26,10 +26,9 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, nextTick, onMounted, provide, ref, watch } from 'vue'
|
||||
import { hideOverlay, showOverlay } from '@/utils'
|
||||
import { commonStore, preferenceStore as preferences, queueStore } from '@/stores'
|
||||
import { authService, socketListener, socketService, uploadService } from '@/services'
|
||||
import { CurrentSongKey, DialogBoxKey, MessageToasterKey } from '@/symbols'
|
||||
import { CurrentSongKey, DialogBoxKey, MessageToasterKey, OverlayKey } from '@/symbols'
|
||||
import { useNetworkStatus, useRouter } from '@/composables'
|
||||
|
||||
import DialogBox from '@/components/ui/DialogBox.vue'
|
||||
|
@ -56,6 +55,7 @@ const CreateNewPlaylistContextMenu = defineAsyncComponent(() => import('@/compon
|
|||
const SupportKoel = defineAsyncComponent(() => import('@/components/meta/SupportKoel.vue'))
|
||||
const DropZone = defineAsyncComponent(() => import('@/components/ui/upload/DropZone.vue'))
|
||||
|
||||
const overlay = ref<InstanceType<typeof Overlay>>()
|
||||
const dialog = ref<InstanceType<typeof DialogBox>>()
|
||||
const toaster = ref<InstanceType<typeof MessageToaster>>()
|
||||
const currentSong = ref<Song | null>(null)
|
||||
|
@ -92,7 +92,7 @@ onMounted(async () => {
|
|||
})
|
||||
|
||||
const init = async () => {
|
||||
showOverlay()
|
||||
overlay.value.show()
|
||||
|
||||
try {
|
||||
await commonStore.init()
|
||||
|
@ -108,8 +108,7 @@ const init = async () => {
|
|||
})
|
||||
|
||||
await socketService.init() && socketListener.listen()
|
||||
|
||||
hideOverlay()
|
||||
overlay.value.hide()
|
||||
} catch (err) {
|
||||
authenticated.value = false
|
||||
throw err
|
||||
|
@ -125,6 +124,7 @@ watch(() => queueStore.current, song => song && (currentSong.value = song))
|
|||
const onDragEnd = () => (showDropZone.value = false)
|
||||
const onDrop = () => (showDropZone.value = false)
|
||||
|
||||
provide(OverlayKey, overlay)
|
||||
provide(DialogBoxKey, dialog)
|
||||
provide(MessageToasterKey, toaster)
|
||||
provide(CurrentSongKey, currentSong)
|
||||
|
|
|
@ -6,8 +6,8 @@ import { defineComponent, nextTick } from 'vue'
|
|||
import { commonStore, userStore } from '@/stores'
|
||||
import { http } from '@/services'
|
||||
import factory from '@/__tests__/factory'
|
||||
import { DialogBoxKey, MessageToasterKey, RouterKey } from '@/symbols'
|
||||
import { DialogBoxStub, MessageToasterStub } from '@/__tests__/stubs'
|
||||
import { DialogBoxKey, MessageToasterKey, OverlayKey, RouterKey } from '@/symbols'
|
||||
import { DialogBoxStub, MessageToasterStub, OverlayStub } from '@/__tests__/stubs'
|
||||
import { routes } from '@/config'
|
||||
import Router from '@/router'
|
||||
|
||||
|
@ -114,6 +114,12 @@ export default abstract class UnitTestCase {
|
|||
options.global.provide[MessageToasterKey] = MessageToasterStub
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
if (!options.global.provide.hasOwnProperty(OverlayKey)) {
|
||||
// @ts-ignore
|
||||
options.global.provide[OverlayKey] = OverlayStub
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
if (!options.global.provide.hasOwnProperty(RouterKey)) {
|
||||
// @ts-ignore
|
||||
|
|
|
@ -3,6 +3,7 @@ import { noop } from '@/utils'
|
|||
|
||||
import MessageToaster from '@/components/ui/MessageToaster.vue'
|
||||
import DialogBox from '@/components/ui/DialogBox.vue'
|
||||
import Overlay from '@/components/ui/Overlay.vue'
|
||||
|
||||
export const MessageToasterStub: Ref<InstanceType<typeof MessageToaster>> = ref({
|
||||
info: noop,
|
||||
|
@ -18,3 +19,8 @@ export const DialogBoxStub: Ref<InstanceType<typeof DialogBox>> = ref({
|
|||
error: noop,
|
||||
confirm: noop
|
||||
})
|
||||
|
||||
export const OverlayStub: Ref<InstanceType<typeof Overlay>> = ref({
|
||||
show: noop,
|
||||
hide: noop
|
||||
})
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { settingStore } from '@/stores'
|
||||
import { forceReloadWindow, hideOverlay, parseValidationError, showOverlay } from '@/utils'
|
||||
import { useDialogBox, useMessageToaster, useRouter } from '@/composables'
|
||||
import { forceReloadWindow, parseValidationError } from '@/utils'
|
||||
import { useDialogBox, useMessageToaster, useOverlay, useRouter } from '@/composables'
|
||||
|
||||
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
||||
import Btn from '@/components/ui/Btn.vue'
|
||||
|
@ -40,6 +40,7 @@ import Btn from '@/components/ui/Btn.vue'
|
|||
const { toastSuccess } = useMessageToaster()
|
||||
const { showConfirmDialog, showErrorDialog } = useDialogBox()
|
||||
const { go } = useRouter()
|
||||
const { showOverlay, hideOverlay } = useOverlay()
|
||||
|
||||
const mediaPath = ref(settingStore.state.media_path)
|
||||
const originalMediaPath = mediaPath.value
|
||||
|
|
|
@ -6,6 +6,7 @@ import { EditSongFormInitialTabKey, SongsKey } from '@/symbols'
|
|||
import { ref } from 'vue'
|
||||
import { fireEvent } from '@testing-library/vue'
|
||||
import { songStore } from '@/stores'
|
||||
import { MessageToasterStub } from '@/__tests__/stubs'
|
||||
import EditSongForm from './EditSongForm.vue'
|
||||
|
||||
let songs: Song[]
|
||||
|
@ -32,6 +33,7 @@ new class extends UnitTestCase {
|
|||
it('edits a single song', async () => {
|
||||
const updateMock = this.mock(songStore, 'update')
|
||||
const emitMock = this.mock(eventBus, 'emit')
|
||||
const alertMock = this.mock(MessageToasterStub.value, 'success')
|
||||
|
||||
const { html, getByTestId, getByRole } = await this.renderComponent(factory<Song>('song', {
|
||||
title: 'Rocket to Heaven',
|
||||
|
@ -67,12 +69,14 @@ new class extends UnitTestCase {
|
|||
year: 1971
|
||||
})
|
||||
|
||||
expect(alertMock).toHaveBeenCalledWith('Updated 1 song.')
|
||||
expect(emitMock).toHaveBeenCalledWith('SONGS_UPDATED')
|
||||
})
|
||||
|
||||
it('edits multiple songs', async () => {
|
||||
const updateMock = this.mock(songStore, 'update')
|
||||
const emitMock = this.mock(eventBus, 'emit')
|
||||
const alertMock = this.mock(MessageToasterStub.value, 'success')
|
||||
|
||||
const { html, getByTestId, getByRole, queryByTestId } = await this.renderComponent(factory<Song>('song', 3))
|
||||
|
||||
|
@ -100,6 +104,7 @@ new class extends UnitTestCase {
|
|||
year: 1990
|
||||
})
|
||||
|
||||
expect(alertMock).toHaveBeenCalledWith('Updated 3 songs.')
|
||||
expect(emitMock).toHaveBeenCalledWith('SONGS_UPDATED')
|
||||
})
|
||||
|
||||
|
|
|
@ -269,6 +269,7 @@ new class extends UnitTestCase {
|
|||
|
||||
it('deletes song', async () => {
|
||||
const confirmMock = this.mock(DialogBoxStub.value, 'confirm', true)
|
||||
const toasterMock = this.mock(MessageToasterStub.value, 'success')
|
||||
const deleteMock = this.mock(songStore, 'deleteFromFilesystem')
|
||||
const { getByText } = await this.actingAsAdmin().renderComponent()
|
||||
|
||||
|
@ -279,6 +280,7 @@ new class extends UnitTestCase {
|
|||
await waitFor(() => {
|
||||
expect(confirmMock).toHaveBeenCalled()
|
||||
expect(deleteMock).toHaveBeenCalledWith(songs)
|
||||
expect(toasterMock).toHaveBeenCalledWith('Deleted 5 songs from the filesystem.')
|
||||
expect(emitMock).toHaveBeenCalledWith('SONGS_DELETED', songs)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
import UnitTestCase from '@/__tests__/UnitTestCase'
|
||||
import { expect, it } from 'vitest'
|
||||
import { eventBus } from '@/utils'
|
||||
import SoundBars from '@/components/ui/SoundBars.vue'
|
||||
import Overlay from './Overlay.vue'
|
||||
|
||||
new class extends UnitTestCase {
|
||||
private async renderComponent (type: OverlayState['type'] = 'loading') {
|
||||
const rendered = this.render(Overlay, {
|
||||
global: {
|
||||
stubs: {
|
||||
SoundBars
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
eventBus.emit('SHOW_OVERLAY', {
|
||||
type,
|
||||
message: 'Look at me now'
|
||||
})
|
||||
|
||||
await this.tick()
|
||||
|
||||
return rendered
|
||||
}
|
||||
|
||||
protected test () {
|
||||
it.each<[OverlayState['type']]>([
|
||||
['loading'],
|
||||
['success'],
|
||||
['info'],
|
||||
['warning'],
|
||||
['error']
|
||||
])('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 { getByTestId } = await this.renderComponent()
|
||||
|
||||
eventBus.emit('HIDE_OVERLAY')
|
||||
expect((getByTestId('overlay') as HTMLDialogElement).open).toBe(false)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -15,7 +15,6 @@
|
|||
<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'
|
||||
|
||||
const SoundBars = defineAsyncComponent(() => import('@/components/ui/SoundBars.vue'))
|
||||
|
||||
|
@ -24,7 +23,7 @@ const el = ref<HTMLDialogElement>()
|
|||
const state = reactive<OverlayState>({
|
||||
dismissible: false,
|
||||
type: 'loading',
|
||||
message: ''
|
||||
message: 'Just a little patience…'
|
||||
})
|
||||
|
||||
const show = (options: Partial<OverlayState> = {}) => {
|
||||
|
@ -35,8 +34,7 @@ const show = (options: Partial<OverlayState> = {}) => {
|
|||
const hide = () => el.value?.close()
|
||||
const onCancel = () => state.dismissible && hide()
|
||||
|
||||
eventBus.on('SHOW_OVERLAY', options => show(options))
|
||||
.on('HIDE_OVERLAY', () => hide())
|
||||
defineExpose({ show, hide })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
// Vitest Snapshot v1
|
||||
|
||||
exports[`renders error type 1`] = `
|
||||
<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" data-v-889cac1d="">Look at me now</span>
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
||||
|
||||
exports[`renders info type 1`] = `
|
||||
<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]" data-v-889cac1d="">
|
||||
<!--v-if--><span class="message" data-v-889cac1d="">Look at me now</span>
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
||||
|
||||
exports[`renders loading type 1`] = `
|
||||
<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" data-v-889cac1d="">Look at me now</span>
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
||||
|
||||
exports[`renders success type 1`] = `
|
||||
<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]" data-v-889cac1d=""><span class="message" data-v-889cac1d="">Look at me now</span>
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
||||
|
||||
exports[`renders warning type 1`] = `
|
||||
<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]" data-v-889cac1d="">
|
||||
<!--v-if-->
|
||||
<!--v-if--><span class="message" data-v-889cac1d="">Look at me now</span>
|
||||
</div>
|
||||
</dialog>
|
||||
`;
|
|
@ -2,12 +2,14 @@ import { expect, it } from 'vitest'
|
|||
import UnitTestCase from '@/__tests__/UnitTestCase'
|
||||
import { fireEvent, waitFor } from '@testing-library/vue'
|
||||
import { userStore } from '@/stores'
|
||||
import { MessageToasterStub } from '@/__tests__/stubs'
|
||||
import AddUserForm from './AddUserForm.vue'
|
||||
|
||||
new class extends UnitTestCase {
|
||||
protected test () {
|
||||
it('creates a new user', async () => {
|
||||
const storeMock = this.mock(userStore, 'store')
|
||||
const alertMock = this.mock(MessageToasterStub.value, 'success')
|
||||
|
||||
const { getByLabelText, getByRole } = this.render(AddUserForm)
|
||||
|
||||
|
@ -24,6 +26,8 @@ new class extends UnitTestCase {
|
|||
password: 'secret-password',
|
||||
is_admin: true
|
||||
})
|
||||
|
||||
expect(alertMock).toHaveBeenCalledWith('New user "John Doe" created.')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,12 +5,14 @@ import UnitTestCase from '@/__tests__/UnitTestCase'
|
|||
import { UserKey } from '@/symbols'
|
||||
import { fireEvent, waitFor } from '@testing-library/vue'
|
||||
import { userStore } from '@/stores'
|
||||
import { MessageToasterStub } from '@/__tests__/stubs'
|
||||
import EditUserForm from './EditUserForm.vue'
|
||||
|
||||
new class extends UnitTestCase {
|
||||
protected test () {
|
||||
it('edits a user', async () => {
|
||||
const updateMock = this.mock(userStore, 'update')
|
||||
const alertMock = this.mock(MessageToasterStub.value, 'success')
|
||||
|
||||
const user = ref(factory<User>('user', { name: 'John Doe' }))
|
||||
|
||||
|
@ -33,6 +35,8 @@ new class extends UnitTestCase {
|
|||
is_admin: user.value.is_admin,
|
||||
password: 'new-password-duck'
|
||||
})
|
||||
|
||||
expect(alertMock).toHaveBeenCalledWith('User profile updated.')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Global event listeners (basically, those without a Vue instance access) go here.
|
||||
*/
|
||||
|
||||
import { defineComponent } from 'vue'
|
||||
import { defineComponent, onMounted } from 'vue'
|
||||
import { authService } from '@/services'
|
||||
import { playlistFolderStore, playlistStore, userStore } from '@/stores'
|
||||
import { eventBus, forceReloadWindow } from '@/utils'
|
||||
|
@ -10,9 +10,15 @@ import { useDialogBox, useMessageToaster, useRouter } from '@/composables'
|
|||
|
||||
export const GlobalEventListeners = defineComponent({
|
||||
setup (props, { slots }) {
|
||||
const { toastSuccess } = useMessageToaster()
|
||||
const { showConfirmDialog } = useDialogBox()
|
||||
const { go } = useRouter()
|
||||
let toastSuccess: ReturnType<typeof useMessageToaster>['toastSuccess']
|
||||
let showConfirmDialog: ReturnType<typeof useDialogBox>['showConfirmDialog']
|
||||
let go: ReturnType<typeof useRouter>['go']
|
||||
|
||||
onMounted(() => {
|
||||
toastSuccess = useMessageToaster().toastSuccess
|
||||
showConfirmDialog = useDialogBox().showConfirmDialog
|
||||
go = useRouter().go
|
||||
})
|
||||
|
||||
eventBus.on('PLAYLIST_DELETE', async playlist => {
|
||||
if (await showConfirmDialog(`Delete the playlist "${playlist.name}"?`)) {
|
||||
|
|
|
@ -7,6 +7,7 @@ export * from './useInfiniteScroll'
|
|||
export * from './useMessageToaster'
|
||||
export * from './useNetworkStatus'
|
||||
export * from './useNewVersionNotification'
|
||||
export * from './useOverlay'
|
||||
export * from './usePlaylistManagement'
|
||||
export * from './useRouter'
|
||||
export * from './useSmartPlaylistForm'
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
import { Ref } from 'vue'
|
||||
import { requireInjection } from '@/utils'
|
||||
import { DialogBoxKey } from '@/symbols'
|
||||
import DialogBox from '@/components/ui/DialogBox.vue'
|
||||
|
||||
let dialogBox: Ref<InstanceType<typeof DialogBox>>
|
||||
|
||||
export const useDialogBox = () => {
|
||||
const dialogBox = requireInjection(DialogBoxKey)
|
||||
dialogBox = dialogBox || requireInjection(DialogBoxKey)
|
||||
|
||||
return {
|
||||
showSuccessDialog: (message: string, title: string = '') => dialogBox.value.success(message, title),
|
||||
showInfoDialog: (message: string, title: string = '') => dialogBox.value.info(message, title),
|
||||
showWarningDialog: (message: string, title: string = '') => dialogBox.value.warning(message, title),
|
||||
showErrorDialog: (message: string, title: string = '') => dialogBox.value.error(message, title),
|
||||
showConfirmDialog: (message: string, title: string = '') => dialogBox.value.confirm(message, title)
|
||||
showSuccessDialog: dialogBox.value.success.bind(dialogBox.value),
|
||||
showInfoDialog: dialogBox.value.info.bind(dialogBox.value),
|
||||
showWarningDialog: dialogBox.value.warning.bind(dialogBox.value),
|
||||
showErrorDialog: dialogBox.value.error.bind(dialogBox.value),
|
||||
showConfirmDialog: dialogBox.value.confirm.bind(dialogBox.value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
import { Ref } from 'vue'
|
||||
import { MessageToasterKey } from '@/symbols'
|
||||
import { requireInjection } from '@/utils'
|
||||
import MessageToaster from '@/components/ui/MessageToaster.vue'
|
||||
|
||||
let toaster: Ref<InstanceType<typeof MessageToaster>>
|
||||
|
||||
export const useMessageToaster = () => {
|
||||
const toaster = requireInjection(MessageToasterKey)
|
||||
toaster = toaster || requireInjection(MessageToasterKey)
|
||||
|
||||
return {
|
||||
toastSuccess: (content: string, timeout?: number) => toaster.value.success(content, timeout),
|
||||
toastInfo: (content: string, timeout?: number) => toaster.value.info(content, timeout),
|
||||
toastWarning: (content: string, timeout?: number) => toaster.value.warning(content, timeout),
|
||||
toastError: (content: string, timeout?: number) => toaster.value.error(content, timeout)
|
||||
toastSuccess: toaster.value.success.bind(toaster.value),
|
||||
toastInfo: toaster.value.info.bind(toaster.value),
|
||||
toastWarning: toaster.value.warning.bind(toaster.value),
|
||||
toastError: toaster.value.error.bind(toaster.value)
|
||||
}
|
||||
}
|
||||
|
|
15
resources/assets/js/composables/useOverlay.ts
Normal file
15
resources/assets/js/composables/useOverlay.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { Ref } from 'vue'
|
||||
import { requireInjection } from '@/utils'
|
||||
import { OverlayKey } from '@/symbols'
|
||||
import Overlay from '@/components/ui/Overlay.vue'
|
||||
|
||||
let overlay: Ref<InstanceType<typeof Overlay>>
|
||||
|
||||
export const useOverlay = () => {
|
||||
overlay = overlay || requireInjection(OverlayKey)
|
||||
|
||||
return {
|
||||
showOverlay: overlay.value.show.bind(overlay.value),
|
||||
hideOverlay: overlay.value.hide.bind(overlay.value)
|
||||
}
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
import { RouterKey } from '@/symbols'
|
||||
import { requireInjection } from '@/utils'
|
||||
import Router from '@/router'
|
||||
|
||||
let router: Router
|
||||
|
||||
export const useRouter = () => {
|
||||
const router = requireInjection(RouterKey)
|
||||
router = router || requireInjection(RouterKey)
|
||||
|
||||
const getRouteParam = (name: string) => router.$currentRoute.value?.params?.[name]
|
||||
const getCurrentScreen = () => router.$currentRoute.value?.screen
|
||||
|
@ -20,6 +23,6 @@ export const useRouter = () => {
|
|||
go: router.go.bind(router),
|
||||
onRouteChanged: router.onRouteChanged.bind(router),
|
||||
resolveRoute: router.resolve.bind(router),
|
||||
triggerNotFound: router.triggerNotFound.bind(router),
|
||||
triggerNotFound: router.triggerNotFound.bind(router)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ import { Ref } from 'vue'
|
|||
export interface Events {
|
||||
LOG_OUT: () => void
|
||||
TOGGLE_SIDEBAR: () => void
|
||||
SHOW_OVERLAY: (options: Partial<OverlayState>) => void
|
||||
HIDE_OVERLAY: () => void
|
||||
FOCUS_SEARCH_FIELD: () => void
|
||||
PLAY_YOUTUBE_VIDEO: (payload: { id: string, title: string }) => void
|
||||
SEARCH_KEYWORDS_CHANGED: (keywords: string) => void
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { DeepReadonly, InjectionKey, Ref } from 'vue'
|
||||
import Overlay from '@/components/ui/Overlay.vue'
|
||||
import DialogBox from '@/components/ui/DialogBox.vue'
|
||||
import MessageToaster from '@/components/ui/MessageToaster.vue'
|
||||
import Router from '@/router'
|
||||
|
@ -6,6 +7,7 @@ import Router from '@/router'
|
|||
export type ReadonlyInjectionKey<T> = InjectionKey<[Readonly<T> | DeepReadonly<T>, Closure]>
|
||||
|
||||
export const RouterKey: InjectionKey<Router> = Symbol('Router')
|
||||
export const OverlayKey: InjectionKey<Ref<InstanceType<typeof Overlay>>> = Symbol('Overlay')
|
||||
export const DialogBoxKey: InjectionKey<Ref<InstanceType<typeof DialogBox>>> = Symbol('DialogBox')
|
||||
export const MessageToasterKey: InjectionKey<Ref<InstanceType<typeof MessageToaster>>> = Symbol('MessageToaster')
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import select from 'select'
|
||||
import { eventBus, noop } from '@/utils'
|
||||
import { noop } from '@/utils'
|
||||
import defaultCover from '@/../img/covers/default.svg'
|
||||
|
||||
export { defaultCover }
|
||||
|
@ -17,14 +17,6 @@ export const forceReloadWindow = (): void => {
|
|||
window.location.reload()
|
||||
}
|
||||
|
||||
export const showOverlay = (
|
||||
message = 'Just a little patience…',
|
||||
type: OverlayState['type'] = 'loading',
|
||||
dismissible = false
|
||||
) => eventBus.emit('SHOW_OVERLAY', { message, type, dismissible })
|
||||
|
||||
export const hideOverlay = () => eventBus.emit('HIDE_OVERLAY')
|
||||
|
||||
export const copyText = (text: string): void => {
|
||||
let copyArea = document.querySelector<HTMLTextAreaElement>('#copyArea')
|
||||
|
||||
|
|
Loading…
Reference in a new issue