@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.
Files changed (23) hide show
  1. package/dist/nuxt/module.json +1 -1
  2. package/dist/nuxt/module.mjs +1 -1
  3. package/dist/plugins/MagicCommand/src/components/MagicCommandDrawer.vue +1 -0
  4. package/dist/plugins/MagicCommand/src/components/MagicCommandModal.vue +1 -0
  5. package/dist/plugins/MagicCookie/src/components/MagicCookie.vue +1 -1
  6. package/dist/plugins/MagicDrawer/src/components/MagicDrawer.vue +1 -1
  7. package/dist/plugins/MagicPlayer/index.mjs +4 -0
  8. package/dist/plugins/MagicPlayer/src/components/MagicAudioPlayer.vue +85 -0
  9. package/dist/plugins/MagicPlayer/src/components/MagicAudioPlayer.vue.d.ts +40 -0
  10. package/dist/plugins/MagicPlayer/src/components/MagicAudioPlayerControls.vue +98 -0
  11. package/dist/plugins/MagicPlayer/src/components/MagicAudioPlayerControls.vue.d.ts +24 -0
  12. package/dist/plugins/MagicPlayer/src/components/MagicPlayer.vue +2 -2
  13. package/dist/plugins/MagicPlayer/src/components/MagicPlayerControls.vue +2 -2
  14. package/dist/plugins/MagicPlayer/src/components/MagicPlayerCurrentTime.vue +54 -0
  15. package/dist/plugins/MagicPlayer/src/components/MagicPlayerCurrentTime.vue.d.ts +14 -0
  16. package/dist/plugins/MagicPlayer/src/components/MagicPlayerOverlay.vue +1 -1
  17. package/dist/plugins/MagicPlayer/src/components/MagicPlayerTimeline.vue +1 -6
  18. package/dist/plugins/MagicPlayer/src/composables/private/usePlayerAudioApi.d.ts +17 -0
  19. package/dist/plugins/MagicPlayer/src/composables/private/usePlayerAudioApi.mjs +82 -0
  20. package/dist/plugins/MagicPlayer/src/composables/private/usePlayerMediaApi.d.ts +5 -0
  21. package/dist/plugins/MagicPlayer/src/composables/private/usePlayerMediaApi.mjs +9 -1
  22. package/dist/plugins/MagicPlayer/src/composables/usePlayerApi.d.ts +5 -0
  23. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@maas/vue-equipment/nuxt",
3
3
  "configKey": "vueEquipment",
4
- "version": "0.23.0"
4
+ "version": "0.23.2"
5
5
  }
@@ -46,7 +46,7 @@ const functions$1 = [
46
46
  {
47
47
  name: "MagicPlayer",
48
48
  "package": "plugins",
49
- lastUpdated: 1707404937000,
49
+ lastUpdated: 1709136225000,
50
50
  docs: "https://maas.egineering/vue-equipment/plugins/MagicPlayer/",
51
51
  description: "player"
52
52
  },
@@ -44,5 +44,6 @@ useDrawerEmitter().on('afterLeave', afterLeaveCallback)
44
44
 
45
45
  onBeforeUnmount(() => {
46
46
  useDrawerEmitter().off('afterLeave', afterLeaveCallback)
47
+ close()
47
48
  })
48
49
  </script>
@@ -44,5 +44,6 @@ useModalEmitter().on('afterLeave', afterLeaveCallback)
44
44
 
45
45
  onBeforeUnmount(() => {
46
46
  useModalEmitter().off('afterLeave', afterLeaveCallback)
47
+ close()
47
48
  })
48
49
  </script>
@@ -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-color: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-color:#fff;--magic-cookie-button-primary-border-color:transparent;--magic-cookie-button-secondary-color:#fff;--magic-cookie-button-secondary-background-color: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-color);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-color);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-color);border-color:var(--magic-cookie-button-secondary-border-color);color:var(--magic-cookie-button-secondary-color)}
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-min-height:unset;--magic-drawer-min-width:unset;--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));min-height:calc(var(--magic-drawer-min-height, 0px) + var(--magic-drawer-drag-overshoot-y, 0px));min-width:calc(var(--magic-drawer-min-width, 0px) + var(--magic-drawer-drag-overshoot-x, 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}
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-player-video"
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-player-video{height:100%;left:0;-o-object-fit:cover;object-fit:cover;position:absolute;top:0;width:100%}
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-color:rgba(32,32,32,.8);--magic-player-controls-backdrop-filter:blur(80px);--magic-player-controls-color:#fff;--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(
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-color);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-height)}.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-color:unset;--magic-player-controls-border-radius:unset;--magic-player-controls-background-color: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}
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-color: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);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}
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-bg-color:hsla(0,0%,98%,.15);--magic-player-thumb-size:1rem;--magic-player-thumb-bg-color:#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-bg-color);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-bg-color);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%)}
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.23.1",
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.2"
53
+ "universal-cookie": "^7.1.0"
54
54
  },
55
55
  "peerDependenciesMeta": {
56
56
  "@maas/magic-timer": {