@maas/vue-equipment 0.23.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nuxt/module.json +1 -1
- package/dist/nuxt/module.mjs +1 -1
- package/dist/plugins/MagicCommand/src/components/MagicCommandDrawer.vue +1 -0
- package/dist/plugins/MagicCommand/src/components/MagicCommandModal.vue +1 -0
- package/dist/plugins/MagicCookie/src/components/MagicCookie.vue +1 -1
- package/dist/plugins/MagicDrawer/src/components/MagicDrawer.vue +1 -1
- package/dist/plugins/MagicPlayer/index.mjs +4 -0
- package/dist/plugins/MagicPlayer/src/components/MagicAudioPlayer.vue +85 -0
- package/dist/plugins/MagicPlayer/src/components/MagicAudioPlayer.vue.d.ts +40 -0
- package/dist/plugins/MagicPlayer/src/components/MagicAudioPlayerControls.vue +98 -0
- package/dist/plugins/MagicPlayer/src/components/MagicAudioPlayerControls.vue.d.ts +24 -0
- package/dist/plugins/MagicPlayer/src/components/MagicPlayer.vue +2 -2
- package/dist/plugins/MagicPlayer/src/components/MagicPlayerControls.vue +2 -2
- package/dist/plugins/MagicPlayer/src/components/MagicPlayerCurrentTime.vue +54 -0
- package/dist/plugins/MagicPlayer/src/components/MagicPlayerCurrentTime.vue.d.ts +14 -0
- package/dist/plugins/MagicPlayer/src/components/MagicPlayerOverlay.vue +1 -1
- package/dist/plugins/MagicPlayer/src/components/MagicPlayerTimeline.vue +1 -6
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerAudioApi.d.ts +17 -0
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerAudioApi.mjs +82 -0
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerMediaApi.d.ts +5 -0
- package/dist/plugins/MagicPlayer/src/composables/private/usePlayerMediaApi.mjs +9 -1
- package/dist/plugins/MagicPlayer/src/composables/usePlayerApi.d.ts +5 -0
- package/package.json +2 -2
package/dist/nuxt/module.json
CHANGED
package/dist/nuxt/module.mjs
CHANGED
|
@@ -114,5 +114,5 @@ const {
|
|
|
114
114
|
</script>
|
|
115
115
|
|
|
116
116
|
<style>
|
|
117
|
-
:root{--magic-cookie-max-width:480px;--magic-cookie-max-height:calc(100vh - 2rem);--magic-cookie-background
|
|
117
|
+
:root{--magic-cookie-max-width:480px;--magic-cookie-max-height:calc(100vh - 2rem);--magic-cookie-background:rgba(75,75,75,.5);--magic-cookie-backdrop-filter:blur(32px);--magic-cookie-color:#fff;--magic-cookie-border-radius:0;--magic-cookie-box-shadow:none;--magic-cookie-preferences-mask:linear-gradient(0deg,hsla(0,0%,100%,0),#fff 1.5rem);--magic-cookie-checkbox-size:0.875rem;--magic-cookie-checkbox-border-width:1px;--magic-cookie-checkbox-border-color:currentColor;--magic-cookie-checkbox-border-radius:0;--magic-cookie-button-width:auto;--magic-cookie-button-height:2.5rem;--magic-cookie-button-spacing:1rem;--magic-cookie-button-border-width:1px;--magic-cookie-button-border-radius:0.25rem;--magic-cookie-button-backdrop-filter:none;--magic-cookie-button-primary-color:#000;--magic-cookie-button-primary-background:#fff;--magic-cookie-button-primary-border-color:transparent;--magic-cookie-button-secondary-color:#fff;--magic-cookie-button-secondary-background:transparent;--magic-cookie-button-secondary-border-color:transparent}.magic-cookie{backdrop-filter:var(--magic-cookie-backdrop-filter);-webkit-backdrop-filter:var(--magic-cookie-backdrop-filter);background-color:var(--magic-cookie-background);border-radius:var(--magic-cookie-border-radius);box-shadow:var(--magic-cookie-box-shadow);color:var(--magic-cookie-color);max-width:var(--magic-cookie-max-width);overflow:hidden}.magic-cookie,.magic-cookie__container{display:flex;flex-direction:column;width:100%}.magic-cookie__container{max-height:var(--magic-cookie-max-height)}.magic-cookie__body{display:flex;flex-direction:column;gap:1rem;height:100%;mask:var(--magic-cookie-preferences-mask);-webkit-mask:var(--magic-cookie-preferences-mask);overflow-y:scroll;padding:1rem;width:100%;-webkit-overflow-scrolling:touch;scroll-behavior:smooth;-ms-overflow-style:none;scrollbar-width:none}.magic-cookie__body::-webkit-scrollbar{display:none}.magic-cookie__footer{padding:1rem;width:100%}.magic-cookie__preferences{flex-direction:column;height:100%}.magic-cookie__actions,.magic-cookie__preferences{display:flex;gap:1rem;width:100%}ul.magic-cookie__cookies{display:flex;flex-direction:column;gap:1rem;list-style:none;margin:0;padding:0}li.magic-cookie__cookie{align-items:flex-start;display:flex;gap:1rem;margin:0;padding:0}.magic-cookie__cookie__content{align-items:flex-start;display:flex;flex-direction:column;gap:.25rem}.magic-cookie__cookie__title{display:inline-flex}.magic-cookie__cookie__text{white-space:pre-line}.magic-cookie-checkbox{align-items:center;display:flex;gap:.625rem}.magic-cookie-checkbox input[type=checkbox]{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:var(--magic-cookie-checkbox-border-width) var(--magic-cookie-checkbox-border-color) solid;border-radius:var(--magic-cookie-checkbox-border-radius);cursor:pointer;flex-shrink:0;height:var(--magic-cookie-checkbox-size);position:relative;vertical-align:middle;width:var(--magic-cookie-checkbox-size)}.magic-cookie-checkbox input[type=checkbox]:checked:after{background-color:var(--magic-cookie-checkbox-border-color);border-radius:var(--magic-cookie-checkbox-border-radius);content:"";display:block;height:calc(var(--magic-cookie-checkbox-size)/2);left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:calc(var(--magic-cookie-checkbox-size)/2)}.magic-cookie-checkbox:disabled{cursor:not-allowed}.magic-cookie-button{align-items:center;backdrop-filter:var(--magic-cookie-button-backdrop-filter);-webkit-backdrop-filter:var(--magic-cookie-button-backdrop-filter);border:var(--magic-cookie-button-border-width) solid;border-radius:var(--magic-cookie-button-border-radius);display:inline-flex;gap:var(--magic-cookie-button-spacing);height:var(--magic-cookie-button-height);justify-content:center;padding:0 var(--magic-cookie-button-spacing);width:var(--magic-cookie-button-width)}.magic-cookie-button.-primary{background-color:var(--magic-cookie-button-primary-background);border-color:var(--magic-cookie-button-primary-border-color);color:var(--magic-cookie-button-primary-color)}.magic-cookie-button.-secondary{background-color:var(--magic-cookie-button-secondary-background);border-color:var(--magic-cookie-button-secondary-border-color);color:var(--magic-cookie-button-secondary-color)}
|
|
118
118
|
</style>
|
|
@@ -291,5 +291,5 @@ onBeforeUnmount(() => {
|
|
|
291
291
|
</script>
|
|
292
292
|
|
|
293
293
|
<style>
|
|
294
|
-
:root{--magic-drawer-height:75svh;--magic-drawer-width:100%;--magic-drawer-
|
|
294
|
+
:root{--magic-drawer-height:75svh;--magic-drawer-width:100%;--magic-drawer-z-index:999;--magic-drawer-justify-content:center;--magic-drawer-align-items:flex-end;--magic-drawer-backdrop-color:rgba(0,0,0,.5);--magic-drawer-backdrop-filter:unset;--magic-drawer-content-overflow-x:hidden;--magic-drawer-content-overflow-y:hidden;--magic-drawer-enter-animation:slide-btt-in 300ms ease;--magic-drawer-leave-animation:slide-btt-out 300ms ease;--magic-drawer-drag-overshoot:4rem;--magic-drawer-padding:0px}.magic-drawer{--magic-drawer-drag-overshoot-x:0px;--magic-drawer-drag-overshoot-y:0px;align-items:var(--magic-drawer-align-items);background:transparent;border:none;color:inherit;display:flex;height:100%;inset:0;justify-content:var(--magic-drawer-justify-content);padding:0;pointer-events:none;position:fixed;width:100%;z-index:var(--magic-drawer-z-index)}.magic-drawer.-bottom{--magic-drawer-drag-overshoot-y:var(--magic-drawer-drag-overshoot);--magic-drawer-padding:0 0 var(--magic-drawer-drag-overshoot-y) 0}.magic-drawer.-top{--magic-drawer-enter-animation:slide-ttb-in 300ms ease;--magic-drawer-leave-animation:slide-ttb-out 300ms ease;--magic-drawer-align-items:flex-start;--magic-drawer-drag-overshoot-y:calc(var(--magic-drawer-drag-overshoot)*-1);--magic-drawer-padding:var(--magic-drawer-drag-overshoot-y) 0 0 0}.magic-drawer.-right{--magic-drawer-enter-animation:slide-rtl-in 300ms ease;--magic-drawer-leave-animation:slide-rtl-out 300ms ease;--magic-drawer-align-items:center;--magic-drawer-justify-content:flex-end;--magic-drawer-drag-overshoot-x:var(--magic-drawer-drag-overshoot);--magic-drawer-padding:0 var(--magic-drawer-drag-overshoot-x) 0 0}.magic-drawer.-left{--magic-drawer-enter-animation:slide-ltr-in 300ms ease;--magic-drawer-leave-animation:slide-ltr-out 300ms ease;--magic-drawer-align-items:center;--magic-drawer-justify-content:flex-start;--magic-drawer-drag-overshoot-x:calc(var(--magic-drawer-drag-overshoot)*-1);--magic-drawer-padding:0 0 0 var(--magic-drawer-drag-overshoot-x)}.magic-drawer__wrapper{height:calc(var(--magic-drawer-height, 0px) + var(--magic-drawer-drag-overshoot-y, 0px));pointer-events:none;transform:translate(var(--magic-drawer-drag-overshoot-x),var(--magic-drawer-drag-overshoot-y));width:calc(var(--magic-drawer-width, 0px) + var(--magic-drawer-drag-overshoot-x, 0px))}.magic-drawer__content{height:100%;max-height:100%;position:relative;width:100%}.magic-drawer__drag{-webkit-overflow-scrolling:touch;align-items:var(--magic-drawer-align-items);cursor:grab;display:flex;height:100%;justify-content:var(--magic-drawer-justify-content);overflow-x:var(--magic-drawer-content-overflow-x);overflow-y:var(--magic-drawer-content-overflow-y);pointer-events:auto;position:relative;scroll-behavior:smooth;width:100%}.magic-drawer.-dragging .magic-drawer__drag{cursor:grabbing;-webkit-user-select:none;-moz-user-select:none;user-select:none}.magic-drawer__drag>*{padding:var(--magic-drawer-padding)}.magic-drawer__overlay{inset:0;position:absolute;z-index:9999}.magic-drawer__backdrop{-webkit-backdrop-filter:var(--magic-drawer-backdrop-filter);backdrop-filter:var(--magic-drawer-backdrop-filter);background-color:var(--magic-drawer-backdrop-color);bottom:0;height:100%;left:0;pointer-events:auto;position:fixed;right:0;top:0;width:100%;z-index:-1}.magic-drawer--content-enter-active{animation:var(--magic-drawer-enter-animation)}.magic-drawer--content-leave-active{animation:var(--magic-drawer-leave-animation)}.magic-drawer--backdrop-enter-active{animation:fade-in .3s ease}.magic-drawer--backdrop-leave-active{animation:fade-out .3s ease}
|
|
295
295
|
</style>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import MagicAudioPlayer from "./src/components/MagicAudioPlayer.vue";
|
|
1
2
|
import MagicPlayer from "./src/components/MagicPlayer.vue";
|
|
2
3
|
import MagicPlayerControls from "./src/components/MagicPlayerControls.vue";
|
|
4
|
+
import MagicPlayerCurrentTime from "./src/components/MagicPlayerCurrentTime.vue";
|
|
3
5
|
import MagicPlayerMuxPopover from "./src/components/MagicPlayerMuxPopover.vue";
|
|
4
6
|
import MagicPlayerOverlay from "./src/components/MagicPlayerOverlay.vue";
|
|
5
7
|
import MagicPlayerPoster from "./src/components/MagicPlayerPoster.vue";
|
|
@@ -7,8 +9,10 @@ import MagicPlayerTimeline from "./src/components/MagicPlayerTimeline.vue";
|
|
|
7
9
|
import { usePlayerApi } from "./src/composables/usePlayerApi.mjs";
|
|
8
10
|
const MagicPlayerPlugin = {
|
|
9
11
|
install: (app) => {
|
|
12
|
+
app.component("MagicAudioPlayer", MagicAudioPlayer);
|
|
10
13
|
app.component("MagicPlayer", MagicPlayer);
|
|
11
14
|
app.component("MagicPlayerControls", MagicPlayerControls);
|
|
15
|
+
app.component("MagicPlayerCurrentTime", MagicPlayerCurrentTime);
|
|
12
16
|
app.component("MagicPlayerMuxPopover", MagicPlayerMuxPopover);
|
|
13
17
|
app.component("MagicPlayerOverlay", MagicPlayerOverlay);
|
|
14
18
|
app.component("MagicPlayerPoster", MagicPlayerPoster);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
ref="playerRef"
|
|
4
|
+
class="magic-audio-player"
|
|
5
|
+
:class="{ '-slot': $slots.default }"
|
|
6
|
+
>
|
|
7
|
+
<div class="magic-audio-player__container">
|
|
8
|
+
<div v-if="$slots.default" class="magic-audio-player__slot">
|
|
9
|
+
<slot />
|
|
10
|
+
</div>
|
|
11
|
+
<magic-audio-player-controls :id="id" />
|
|
12
|
+
</div>
|
|
13
|
+
<audio ref="audioRef" class="magic-audio-player__audio" />
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup lang="ts">
|
|
18
|
+
import MagicAudioPlayerControls from './MagicAudioPlayerControls.vue'
|
|
19
|
+
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
|
20
|
+
import { useIntersectionObserver } from '@vueuse/core'
|
|
21
|
+
import { usePlayerAudioApi } from '../composables/private/usePlayerAudioApi'
|
|
22
|
+
import { usePlayerMediaApi } from '../composables/private/usePlayerMediaApi'
|
|
23
|
+
import { usePlayerRuntime } from '../composables/private/usePlayerRuntime'
|
|
24
|
+
|
|
25
|
+
interface Props {
|
|
26
|
+
id: string
|
|
27
|
+
src: string
|
|
28
|
+
loop?: boolean
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
32
|
+
src: '',
|
|
33
|
+
loop: false,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const playerRef = ref<HTMLDivElement | undefined>(undefined)
|
|
37
|
+
const audioRef = ref<HTMLVideoElement | undefined>(undefined)
|
|
38
|
+
|
|
39
|
+
const pausedByIntersection = ref(false)
|
|
40
|
+
|
|
41
|
+
const { playing } = usePlayerMediaApi({
|
|
42
|
+
id: props.id,
|
|
43
|
+
mediaRef: audioRef,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const { initialize, destroy } = usePlayerRuntime({
|
|
47
|
+
id: props.id,
|
|
48
|
+
mediaRef: audioRef,
|
|
49
|
+
src: props.src,
|
|
50
|
+
srcType: 'native',
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const { play, pause } = usePlayerAudioApi({
|
|
54
|
+
id: props.id,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
useIntersectionObserver(
|
|
58
|
+
playerRef,
|
|
59
|
+
([{ isIntersecting }]) => {
|
|
60
|
+
if (!isIntersecting && playing.value) {
|
|
61
|
+
pause()
|
|
62
|
+
pausedByIntersection.value = true
|
|
63
|
+
} else if (isIntersecting && !playing.value && pausedByIntersection.value) {
|
|
64
|
+
pausedByIntersection.value = false
|
|
65
|
+
|
|
66
|
+
play()
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
immediate: true,
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
onMounted(() => {
|
|
75
|
+
initialize()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
onBeforeUnmount(() => {
|
|
79
|
+
destroy()
|
|
80
|
+
})
|
|
81
|
+
</script>
|
|
82
|
+
|
|
83
|
+
<style>
|
|
84
|
+
:root{--magic-audio-player-color:#fff;--magic-audio-player-background:rgba(32,32,32,.8);--magic-audio-player-background-slot:hsla(0,0%,98%,.15);--magic-audio-player-backdrop-filter:blur(80px);--magic-audio-player-border-radius:1.25rem;--magic-audio-player-padding:0.25rem;--magic-audio-player-gap:0.25rem;--magic-audio-player-slot-padding:0.75rem 1rem;--magic-audio-player-slot-radius:calc(var(--magic-audio-player-border-radius) - var(--magic-audio-player-padding));--magic-audio-player-slot-background:rgba(32,32,32,.8)}.magic-audio-player{-webkit-backdrop-filter:var(--magic-audio-player-backdrop-filter);backdrop-filter:var(--magic-audio-player-backdrop-filter);background:var(--magic-audio-player-background);border-radius:var(--magic-audio-player-border-radius);color:var(--magic-audio-player-color);padding:var(--magic-audio-player-padding);position:relative;width:100%}.magic-audio-player.-slot{background:var(--magic-audio-player-background-slot)}.magic-audio-player__container{display:flex;flex-direction:column;gap:var(--magic-audio-player-gap);height:100%;position:relative;width:100%}.magic-audio-player__slot{background-color:var(--magic-audio-player-background);border-radius:var(--magic-audio-player-slot-radius);color:inherit;padding:var(--magic-audio-player-slot-padding)}.magic-audio-player__audio{width:100%}
|
|
85
|
+
</style>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
id: string;
|
|
3
|
+
src: string;
|
|
4
|
+
loop?: boolean;
|
|
5
|
+
}
|
|
6
|
+
declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
|
|
7
|
+
src: string;
|
|
8
|
+
loop: boolean;
|
|
9
|
+
}>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
|
|
10
|
+
src: string;
|
|
11
|
+
loop: boolean;
|
|
12
|
+
}>>>, {
|
|
13
|
+
src: string;
|
|
14
|
+
loop: boolean;
|
|
15
|
+
}, {}>, {
|
|
16
|
+
default?(_: {}): any;
|
|
17
|
+
}>;
|
|
18
|
+
export default _default;
|
|
19
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
20
|
+
type __VLS_TypePropsToRuntimeProps<T> = {
|
|
21
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
22
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
23
|
+
} : {
|
|
24
|
+
type: import('vue').PropType<T[K]>;
|
|
25
|
+
required: true;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
type __VLS_WithDefaults<P, D> = {
|
|
29
|
+
[K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
|
|
30
|
+
default: D[K];
|
|
31
|
+
}> : P[K];
|
|
32
|
+
};
|
|
33
|
+
type __VLS_Prettify<T> = {
|
|
34
|
+
[K in keyof T]: T[K];
|
|
35
|
+
} & {};
|
|
36
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
37
|
+
new (): {
|
|
38
|
+
$slots: S;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="magic-audio-player-controls"
|
|
4
|
+
:class="{
|
|
5
|
+
'-touched': touched,
|
|
6
|
+
'-untouched': !touched,
|
|
7
|
+
'-playing': playing,
|
|
8
|
+
'-paused': !playing,
|
|
9
|
+
'-waiting': waiting,
|
|
10
|
+
'-idle': idle,
|
|
11
|
+
'-not-idle': !idle,
|
|
12
|
+
'-hover': mouseEntered,
|
|
13
|
+
'-not-hover': !mouseEntered,
|
|
14
|
+
}"
|
|
15
|
+
>
|
|
16
|
+
<div class="magic-audio-player-controls__bar">
|
|
17
|
+
<div class="magic-audio-player-controls__bar--inner" ref="barRef">
|
|
18
|
+
<div class="magic-audio-player-controls__item -shrink-0">
|
|
19
|
+
<button v-if="!playing" @click="play">
|
|
20
|
+
<slot name="playIcon">
|
|
21
|
+
<icon-play />
|
|
22
|
+
</slot>
|
|
23
|
+
</button>
|
|
24
|
+
<button v-else @click="pause">
|
|
25
|
+
<slot name="pauseIcon">
|
|
26
|
+
<icon-pause />
|
|
27
|
+
</slot>
|
|
28
|
+
</button>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="magic-audio-player-controls__item -shrink-0">
|
|
31
|
+
<magic-player-current-time :id="id" />
|
|
32
|
+
</div>
|
|
33
|
+
<div class="magic-audio-player-controls__item -grow">
|
|
34
|
+
<div class="magic-audio-player-controls__timeline" ref="trackRef">
|
|
35
|
+
<magic-player-timeline :id="id" />
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="magic-audio-player-controls__item -shrink-0">
|
|
39
|
+
<button v-if="muted" @click="unmute">
|
|
40
|
+
<slot name="volumeOffIcon">
|
|
41
|
+
<icon-volume-off />
|
|
42
|
+
</slot>
|
|
43
|
+
</button>
|
|
44
|
+
<button v-else @click="mute">
|
|
45
|
+
<slot name="volumeOnIcon">
|
|
46
|
+
<icon-volume-on />
|
|
47
|
+
</slot>
|
|
48
|
+
</button>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<script setup lang="ts">
|
|
56
|
+
import { ref } from 'vue'
|
|
57
|
+
import { useIdle } from '@vueuse/core'
|
|
58
|
+
import IconPlay from './icons/Play.vue'
|
|
59
|
+
import IconPause from './icons/Pause.vue'
|
|
60
|
+
import IconVolumeOn from './icons/VolumeOn.vue'
|
|
61
|
+
import IconVolumeOff from './icons/VolumeOff.vue'
|
|
62
|
+
import { usePlayerMediaApi } from '../composables/private/usePlayerMediaApi'
|
|
63
|
+
import { usePlayerAudioApi } from '../composables/private/usePlayerAudioApi'
|
|
64
|
+
import { usePlayerControlsApi } from '../composables/private/usePlayerControlsApi'
|
|
65
|
+
|
|
66
|
+
interface Props {
|
|
67
|
+
id: string
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const props = defineProps<Props>()
|
|
71
|
+
|
|
72
|
+
const barRef = ref<HTMLDivElement | undefined>(undefined)
|
|
73
|
+
const trackRef = ref<HTMLDivElement | undefined>(undefined)
|
|
74
|
+
|
|
75
|
+
const { playing, waiting, muted } = usePlayerMediaApi({
|
|
76
|
+
id: props.id,
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const { play, pause, mute, unmute, touched, mouseEntered } = usePlayerAudioApi({
|
|
80
|
+
id: props.id,
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const { formattedCurrentTime } = usePlayerMediaApi({
|
|
84
|
+
id: props.id,
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
usePlayerControlsApi({
|
|
88
|
+
id: props.id,
|
|
89
|
+
barRef: barRef,
|
|
90
|
+
trackRef: trackRef,
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const { idle } = useIdle(3000)
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<style>
|
|
97
|
+
:root{--magic-audio-player-controls-height:3rem;--magic-audio-player-controls-padding:0rem;--magic-audio-player-controls-color:inherit;--magic-audio-player-controls-icon-width:1.25rem;--magic-audio-player-controls-button-width:4rem}.magic-audio-player-controls{pointer-events:none;width:100%}.magic-audio-player-controls__bar{align-items:flex-start;display:flex;flex-direction:column;margin:0 auto;pointer-events:auto;width:100%}.magic-audio-player-controls__bar--inner{align-items:center;box-sizing:border-box;color:var(--magic-audio-player-controls-color);display:flex;height:var(--magic-audio-player-controls-height);padding:0 var(--magic-audio-player-controls-padding);width:100%}.magic-audio-player-controls__item{align-items:center;display:inline-flex;-webkit-user-select:none;-moz-user-select:none;user-select:none}.magic-audio-player-controls__item.-shrink-0{flex-shrink:0}.magic-audio-player-controls__item.-grow{flex-grow:1}.magic-audio-player-controls__item button{align-items:center;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:0;border-radius:0;color:inherit;cursor:pointer;display:flex;height:var(--magic-audio-player-controls-height);justify-content:center;outline:none;padding:0;width:var(--magic-audio-player-controls-button-width)}.magic-audio-player-controls__item button svg{display:block;height:auto;width:var(--magic-audio-player-controls-icon-width)}.magic-audio-player-controls__timeline{width:100%}
|
|
98
|
+
</style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
id: string;
|
|
3
|
+
}
|
|
4
|
+
declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__VLS_TypePropsToRuntimeProps<Props>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<Props>>>, {}, {}>, {
|
|
5
|
+
playIcon?(_: {}): any;
|
|
6
|
+
pauseIcon?(_: {}): any;
|
|
7
|
+
volumeOffIcon?(_: {}): any;
|
|
8
|
+
volumeOnIcon?(_: {}): any;
|
|
9
|
+
}>;
|
|
10
|
+
export default _default;
|
|
11
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
12
|
+
type __VLS_TypePropsToRuntimeProps<T> = {
|
|
13
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
14
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
15
|
+
} : {
|
|
16
|
+
type: import('vue').PropType<T[K]>;
|
|
17
|
+
required: true;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
21
|
+
new (): {
|
|
22
|
+
$slots: S;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
>
|
|
9
9
|
<video
|
|
10
10
|
ref="videoRef"
|
|
11
|
-
class="magic-
|
|
11
|
+
class="magic-player__video"
|
|
12
12
|
preload="auto"
|
|
13
13
|
playsinline
|
|
14
14
|
disablePictureInPicture
|
|
@@ -112,5 +112,5 @@ onBeforeUnmount(() => {
|
|
|
112
112
|
</script>
|
|
113
113
|
|
|
114
114
|
<style>
|
|
115
|
-
:root{--magic-player-aspect-ratio:16/9}.magic-player{aspect-ratio:var(--magic-player-aspect-ratio);overflow:hidden;position:relative;width:100%}.magic-
|
|
115
|
+
:root{--magic-player-aspect-ratio:16/9}.magic-player{aspect-ratio:var(--magic-player-aspect-ratio);overflow:hidden;position:relative;width:100%}.magic-player__video{height:100%;left:0;-o-object-fit:cover;object-fit:cover;position:absolute;top:0;width:100%}
|
|
116
116
|
</style>
|
|
@@ -121,7 +121,7 @@ const { idle } = useIdle(3000)
|
|
|
121
121
|
</script>
|
|
122
122
|
|
|
123
123
|
<style>
|
|
124
|
-
:root{--magic-player-controls-height:3rem;--magic-player-controls-padding:0.75rem;--magic-player-controls-bottom:1.5rem;--magic-player-controls-left:1.5rem;--magic-player-controls-width:calc(100% - var(--magic-player-controls-left)*2);--magic-player-controls-gap:1rem;--magic-player-controls-border-radius:50rem;--magic-player-controls-background
|
|
124
|
+
:root{--magic-player-controls-height:3rem;--magic-player-controls-padding:0.75rem;--magic-player-controls-bottom:1.5rem;--magic-player-controls-left:1.5rem;--magic-player-controls-width:calc(100% - var(--magic-player-controls-left)*2);--magic-player-controls-gap:1rem;--magic-player-controls-border-radius:50rem;--magic-player-controls-background:rgba(32,32,32,.8);--magic-player-controls-backdrop-filter:blur(80px);--magic-player-controls-color:#fff;--magic-player-controls-button-width:3rem;--magic-player-controls-icon-width:1.25rem;--magic-player-controls-transition-duration:300ms;--magic-player-controls-transition-timing-function:ease}@media (max-width:640px){:root{--magic-player-controls-height:2.5rem;--magic-player-controls-bottom:0.75rem;--magic-player-controls-padding:0.5rem}}.magic-player-controls{inset:0;pointer-events:none;position:absolute;width:100%}.magic-player-controls__bar{align-items:flex-start;bottom:var(--magic-player-controls-bottom);display:flex;flex-direction:column;gap:var(--magic-player-controls-gap);left:var(--magic-player-controls-left);margin:0 auto;pointer-events:auto;position:absolute;transition-duration:var(--magic-player-controls-transition-duration);transition-property:opacity,transform;transition-timing-function:var(
|
|
125
125
|
--magic-player-controls-transition-timing-function
|
|
126
|
-
);width:var(--magic-player-controls-width)}.magic-player-controls__bar--inner{align-items:center;-webkit-backdrop-filter:var(--magic-player-controls-backdrop-filter);backdrop-filter:var(--magic-player-controls-backdrop-filter);background-color:var(--magic-player-controls-background
|
|
126
|
+
);width:var(--magic-player-controls-width)}.magic-player-controls__bar--inner{align-items:center;-webkit-backdrop-filter:var(--magic-player-controls-backdrop-filter);backdrop-filter:var(--magic-player-controls-backdrop-filter);background-color:var(--magic-player-controls-background);border-radius:var(--magic-player-controls-border-radius);box-sizing:border-box;color:var(--magic-player-controls-color);display:flex;height:var(--magic-player-controls-height);padding:0 var(--magic-player-controls-padding);width:100%}.magic-player-controls__item{align-items:center;display:inline-flex;-webkit-user-select:none;-moz-user-select:none;user-select:none}.magic-player-controls__item.-shrink-0{flex-shrink:0}.magic-player-controls__item.-grow{flex-grow:1}.magic-player-controls__item button{align-items:center;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:0;border-radius:0;color:inherit;cursor:pointer;display:flex;height:var(--magic-player-controls-height);justify-content:center;outline:none;padding:0;width:var(--magic-player-controls-button-width)}.magic-player-controls__item button svg{display:block;height:auto;width:var(--magic-player-controls-icon-width)}.magic-player-controls__timeline{width:100%}.magic-player-controls:not(.-standalone).-playing.-idle .magic-player-controls__bar,.magic-player-controls:not(.-standalone).-playing.-not-hover .magic-player-controls__bar,.magic-player-controls:not(.-standalone).-untouched .magic-player-controls__bar{opacity:0;transform:translateY(25%)}.magic-player-controls.-standalone{inset:unset;position:relative;--magic-player-controls-width:100%;--magic-player-controls-bottom:0;--magic-player-controls-left:0;--magic-player-controls-padding:0;--magic-player-controls-background:unset;--magic-player-controls-border-radius:unset;--magic-player-controls-background:transparent;--magic-player-controls-backdrop-filter:none;--magic-player-controls-transition-duration:unset;--magic-player-controls-transition-timing-function:unset}.magic-player-controls.-standalone .magic-player-controls__bar{position:relative}
|
|
127
127
|
</style>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="magic-player-current-time">
|
|
3
|
+
{{ stringifiedTime }}
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import { computed } from 'vue'
|
|
9
|
+
import { usePlayerMediaApi } from '../composables/private/usePlayerMediaApi'
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
id: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const props = defineProps<Props>()
|
|
16
|
+
|
|
17
|
+
const { formattedCurrentTime } = usePlayerMediaApi({
|
|
18
|
+
id: props.id,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const hours = computed(() => {
|
|
22
|
+
return formattedCurrentTime.value.hours
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const minutes = computed(() => {
|
|
26
|
+
return formattedCurrentTime.value.minutes || '0'
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const seconds = computed(() => {
|
|
30
|
+
return formattedCurrentTime.value.seconds
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const stringifiedTime = computed(() => {
|
|
34
|
+
let time = hours.value ? `${hours.value}:` : ''
|
|
35
|
+
|
|
36
|
+
if (minutes.value.toString().length === 1) {
|
|
37
|
+
time += `0${minutes.value}`
|
|
38
|
+
} else {
|
|
39
|
+
time += `${minutes.value}`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (seconds.value.toString().length === 1) {
|
|
43
|
+
time += `:0${seconds.value}`
|
|
44
|
+
} else {
|
|
45
|
+
time += `:${seconds.value}`
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return time
|
|
49
|
+
})
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<style>
|
|
53
|
+
:root{--magic-player-current-time-font-size:0.875rem;--magic-player-current-time-color:inherit;--magic-player-current-time-width:3.875rem;--magic-player-current-time-justify-content:flex-start}.magic-player-current-time{align-items:center;color:var(--magic-player-current-time-color);display:flex;font-size:var(--magic-player-current-time-font-size);height:100%;justify-content:var(--magic-player-current-time-justify-content);width:var(--magic-player-current-time-width)}
|
|
54
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
id: string;
|
|
3
|
+
}
|
|
4
|
+
declare const _default: import("vue").DefineComponent<__VLS_TypePropsToRuntimeProps<Props>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<Props>>>, {}, {}>;
|
|
5
|
+
export default _default;
|
|
6
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
7
|
+
type __VLS_TypePropsToRuntimeProps<T> = {
|
|
8
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
9
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
10
|
+
} : {
|
|
11
|
+
type: import('vue').PropType<T[K]>;
|
|
12
|
+
required: true;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
@@ -60,5 +60,5 @@ const { idle } = useIdle(3000)
|
|
|
60
60
|
</script>
|
|
61
61
|
|
|
62
62
|
<style>
|
|
63
|
-
:root{--magic-player-overlay-background
|
|
63
|
+
:root{--magic-player-overlay-background:rgba(0,0,0,.3);--magic-player-overlay-color:#fff;--magic-player-overlay-button-size:2.5rem}.magic-player-overlay{align-items:center;background-color:var(--magic-player-overlay-background);color:var(--magic-player-overlay-color);cursor:pointer;display:flex;inset:0;justify-content:center;position:absolute;transition-duration:.3s;transition-property:opacity;transition-timing-function:ease}.magic-player-overlay__button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:0;border-radius:0;color:inherit;cursor:pointer;height:var(--magic-player-overlay-button-size);outline:none;padding:0;width:var(--magic-player-overlay-button-size)}.magic-player-overlay.-playing.-idle,.magic-player-overlay.-playing.-not-hover{opacity:0}
|
|
64
64
|
</style>
|
|
@@ -36,7 +36,6 @@
|
|
|
36
36
|
</template>
|
|
37
37
|
|
|
38
38
|
<script setup lang="ts">
|
|
39
|
-
import { computed } from 'vue'
|
|
40
39
|
import { usePlayerControlsApi } from '../composables/private/usePlayerControlsApi'
|
|
41
40
|
|
|
42
41
|
interface Props {
|
|
@@ -59,12 +58,8 @@ const {
|
|
|
59
58
|
} = usePlayerControlsApi({
|
|
60
59
|
id: props.id,
|
|
61
60
|
})
|
|
62
|
-
|
|
63
|
-
const height = computed(() => {
|
|
64
|
-
return trackRect.value?.height
|
|
65
|
-
})
|
|
66
61
|
</script>
|
|
67
62
|
|
|
68
63
|
<style>
|
|
69
|
-
:root{--magic-player-target-height:56px;--magic-player-track-height:4px;--magic-player-track-
|
|
64
|
+
:root{--magic-player-target-height:56px;--magic-player-track-height:4px;--magic-player-track-background:hsla(0,0%,98%,.15);--magic-player-thumb-size:1rem;--magic-player-thumb-background:#fafafa}.magic-player-timeline{height:var(--magic-player-track-height)}.magic-player-timeline,.magic-player-timeline__target{align-items:center;display:flex;position:relative;width:100%}.magic-player-timeline__target{cursor:pointer;height:var(--magic-player-target-height)}.magic-player-timeline__slider-track{background:var(--magic-player-track-background);border-radius:50rem;height:var(--magic-player-track-height);position:relative;width:100%}.magic-player-timeline__slider-inner-track{border-radius:50rem;height:100%;left:0;overflow:hidden;position:relative;top:0;width:100%;z-index:1}.magic-player-timeline__slider-thumb{height:var(--magic-player-track-height);position:absolute;width:var(--magic-player-track-height);z-index:10}.magic-player-timeline__slider-thumb-handle{background-color:var(--magic-player-thumb-background);border-radius:50rem;height:var(--magic-player-thumb-size);left:50%;position:absolute;top:50%;transform:translate(-50%,-50%) scale(0);transition:transform .3s ease;width:var(--magic-player-thumb-size);z-index:10}.magic-player-timeline__slider-buffered,.magic-player-timeline__slider-scrubbed,.magic-player-timeline__slider-seeked{background:currentColor;border-radius:50rem;height:100%;left:0;margin-left:calc(-100% + var(--magic-player-track-height));position:absolute;width:100%}.magic-player-timeline__slider-scrubbed{display:flex;min-width:var(--magic-player-track-height);z-index:1}.magic-player-timeline__slider-seeked{opacity:.25}.magic-player-timeline__slider-buffered{opacity:.15}.magic-player-timeline:hover .magic-player-timeline__slider-thumb-handle{transform:translate(-50%,-50%) scale(1)}.magic-player-timeline__seek-popover{bottom:100%;left:0;position:absolute;transform:translateX(-50%)}
|
|
70
65
|
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type MaybeRef } from 'vue';
|
|
2
|
+
export type UsePlayerAudioApiArgs = {
|
|
3
|
+
id: MaybeRef<string>;
|
|
4
|
+
};
|
|
5
|
+
export declare function usePlayerAudioApi(args: UsePlayerAudioApiArgs): {
|
|
6
|
+
mouseEntered: import("vue").Ref<boolean>;
|
|
7
|
+
touched: import("vue").Ref<boolean>;
|
|
8
|
+
play: () => void;
|
|
9
|
+
pause: () => void;
|
|
10
|
+
togglePlay: () => void;
|
|
11
|
+
seek: (time: number) => void;
|
|
12
|
+
mute: () => void;
|
|
13
|
+
unmute: () => void;
|
|
14
|
+
onMouseenter: () => void;
|
|
15
|
+
onMouseleave: () => void;
|
|
16
|
+
};
|
|
17
|
+
export type UsePlayerAudioApiReturn = ReturnType<typeof usePlayerAudioApi>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { ref, watch, toValue } from "vue";
|
|
2
|
+
import { usePlayerStateEmitter } from "./usePlayerStateEmitter.mjs";
|
|
3
|
+
import { usePlayerMediaApi } from "./usePlayerMediaApi.mjs";
|
|
4
|
+
export function usePlayerAudioApi(args) {
|
|
5
|
+
const { playing, currentTime, muted } = usePlayerMediaApi({
|
|
6
|
+
id: args.id
|
|
7
|
+
});
|
|
8
|
+
const touched = ref(false);
|
|
9
|
+
const mouseEntered = ref(false);
|
|
10
|
+
function play() {
|
|
11
|
+
playing.value = true;
|
|
12
|
+
}
|
|
13
|
+
function pause() {
|
|
14
|
+
playing.value = false;
|
|
15
|
+
}
|
|
16
|
+
function togglePlay() {
|
|
17
|
+
playing.value = !playing.value;
|
|
18
|
+
}
|
|
19
|
+
function seek(time) {
|
|
20
|
+
currentTime.value = time;
|
|
21
|
+
}
|
|
22
|
+
function mute() {
|
|
23
|
+
muted.value = true;
|
|
24
|
+
}
|
|
25
|
+
function unmute() {
|
|
26
|
+
muted.value = false;
|
|
27
|
+
}
|
|
28
|
+
function onMouseenter() {
|
|
29
|
+
mouseEntered.value = true;
|
|
30
|
+
}
|
|
31
|
+
function onMouseleave() {
|
|
32
|
+
mouseEntered.value = false;
|
|
33
|
+
}
|
|
34
|
+
watch(playing, (value) => {
|
|
35
|
+
if (!touched.value && value) {
|
|
36
|
+
touched.value = true;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
const emitter = usePlayerStateEmitter();
|
|
40
|
+
emitter.on("update", (payload) => {
|
|
41
|
+
if (payload.id !== toValue(args.id))
|
|
42
|
+
return;
|
|
43
|
+
if (payload.api === "player") {
|
|
44
|
+
switch (payload.key) {
|
|
45
|
+
case "mouseEntered":
|
|
46
|
+
mouseEntered.value = payload.value;
|
|
47
|
+
break;
|
|
48
|
+
case "touched":
|
|
49
|
+
touched.value = payload.value;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
watch(mouseEntered, (value) => {
|
|
55
|
+
emitter.emit("update", {
|
|
56
|
+
id: toValue(args.id),
|
|
57
|
+
api: "player",
|
|
58
|
+
key: "mouseEntered",
|
|
59
|
+
value
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
watch(touched, (value) => {
|
|
63
|
+
emitter.emit("update", {
|
|
64
|
+
id: toValue(args.id),
|
|
65
|
+
api: "player",
|
|
66
|
+
key: "touched",
|
|
67
|
+
value
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
mouseEntered,
|
|
72
|
+
touched,
|
|
73
|
+
play,
|
|
74
|
+
pause,
|
|
75
|
+
togglePlay,
|
|
76
|
+
seek,
|
|
77
|
+
mute,
|
|
78
|
+
unmute,
|
|
79
|
+
onMouseenter,
|
|
80
|
+
onMouseleave
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -5,6 +5,11 @@ export type UsePlayerMediaApiArgs = {
|
|
|
5
5
|
};
|
|
6
6
|
export declare function usePlayerMediaApi(args: UsePlayerMediaApiArgs): {
|
|
7
7
|
currentTime: import("vue").Ref<number>;
|
|
8
|
+
formattedCurrentTime: import("vue").ComputedRef<{
|
|
9
|
+
hours: number;
|
|
10
|
+
minutes: number;
|
|
11
|
+
seconds: number;
|
|
12
|
+
}>;
|
|
8
13
|
duration: import("vue").Ref<number>;
|
|
9
14
|
seeking: import("vue").Ref<boolean>;
|
|
10
15
|
volume: import("vue").Ref<number>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ref, watch, unref, toValue } from "vue";
|
|
1
|
+
import { ref, computed, watch, unref, toValue } from "vue";
|
|
2
2
|
import { useEventListener, watchIgnorable } from "@vueuse/core";
|
|
3
3
|
import { usePlayerStateEmitter } from "./usePlayerStateEmitter.mjs";
|
|
4
4
|
export function usePlayerMediaApi(args) {
|
|
@@ -14,6 +14,13 @@ export function usePlayerMediaApi(args) {
|
|
|
14
14
|
const buffered = ref([]);
|
|
15
15
|
const muted = ref(false);
|
|
16
16
|
const { mediaRef } = args;
|
|
17
|
+
const formattedCurrentTime = computed(() => formatTime(currentTime.value));
|
|
18
|
+
function formatTime(currentTime2) {
|
|
19
|
+
const hours = Math.floor(currentTime2 / 3600);
|
|
20
|
+
const minutes = Math.floor(currentTime2 % 3600 / 60);
|
|
21
|
+
const seconds = Math.floor(currentTime2 % 60);
|
|
22
|
+
return { hours, minutes, seconds };
|
|
23
|
+
}
|
|
17
24
|
function timeRangeToArray(timeRanges) {
|
|
18
25
|
let ranges = [];
|
|
19
26
|
for (let i = 0; i < timeRanges.length; ++i)
|
|
@@ -249,6 +256,7 @@ export function usePlayerMediaApi(args) {
|
|
|
249
256
|
});
|
|
250
257
|
return {
|
|
251
258
|
currentTime,
|
|
259
|
+
formattedCurrentTime,
|
|
252
260
|
duration,
|
|
253
261
|
seeking,
|
|
254
262
|
volume,
|
|
@@ -5,6 +5,11 @@ type usePlayerApiArgs = {
|
|
|
5
5
|
export declare function usePlayerApi(args: usePlayerApiArgs): {
|
|
6
6
|
mediaApi: {
|
|
7
7
|
currentTime: import("vue").Ref<number>;
|
|
8
|
+
formattedCurrentTime: import("vue").ComputedRef<{
|
|
9
|
+
hours: number;
|
|
10
|
+
minutes: number;
|
|
11
|
+
seconds: number;
|
|
12
|
+
}>;
|
|
8
13
|
duration: import("vue").Ref<number>;
|
|
9
14
|
seeking: import("vue").Ref<boolean>;
|
|
10
15
|
volume: import("vue").Ref<number>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maas/vue-equipment",
|
|
3
3
|
"description": "A magic collection of Vue composables, plugins, components and directives",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.24.0",
|
|
5
5
|
"author": "Robin Scholz <https://github.com/robinscholz>, Christoph Jeworutzki <https://github.com/ChristophJeworutzki>",
|
|
6
6
|
"devDependencies": {
|
|
7
7
|
"@antfu/ni": "^0.21.12",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"mitt": "^3.0.1",
|
|
51
51
|
"motion": "^10.16.2",
|
|
52
52
|
"nuxt": "^3.5.1",
|
|
53
|
-
"universal-cookie": "^7.0
|
|
53
|
+
"universal-cookie": "^7.1.0"
|
|
54
54
|
},
|
|
55
55
|
"peerDependenciesMeta": {
|
|
56
56
|
"@maas/magic-timer": {
|