mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(skin): show scrubber preview timestamps (#1652)
This commit is contained in:
@@ -85,6 +85,9 @@ function getTemplateHTML() {
|
||||
<media-slider-buffer class="${cn(slider.fill.base, slider.fill.buffer)}"></media-slider-buffer>
|
||||
</media-slider-track>
|
||||
<media-slider-thumb class="${cn(slider.thumb.base, slider.thumb.interactive)}"></media-slider-thumb>
|
||||
<media-slider-preview class="${slider.preview}">
|
||||
<media-slider-value type="pointer" class="${slider.value}"></media-slider-value>
|
||||
</media-slider-preview>
|
||||
</media-time-slider>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -68,6 +68,9 @@ function getTemplateHTML() {
|
||||
<media-slider-buffer class="media-slider__buffer"></media-slider-buffer>
|
||||
</media-slider-track>
|
||||
<media-slider-thumb class="media-slider__thumb"></media-slider-thumb>
|
||||
<media-slider-preview class="media-slider__preview">
|
||||
<media-slider-value type="pointer" class="media-slider__value media-time"></media-slider-value>
|
||||
</media-slider-preview>
|
||||
</media-time-slider>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -80,6 +80,9 @@ function getTemplateHTML() {
|
||||
<media-slider-buffer class="${cn(slider.fill.base, slider.fill.buffer)}"></media-slider-buffer>
|
||||
</media-slider-track>
|
||||
<media-slider-thumb class="${cn(slider.thumb.base, slider.thumb.interactive)}"></media-slider-thumb>
|
||||
<media-slider-preview class="${slider.preview}">
|
||||
<media-slider-value type="pointer" class="${slider.value}"></media-slider-value>
|
||||
</media-slider-preview>
|
||||
</media-time-slider>
|
||||
<media-time type="duration" class="${time.duration}"></media-time>
|
||||
</div>
|
||||
|
||||
@@ -63,6 +63,9 @@ function getTemplateHTML() {
|
||||
<media-slider-buffer class="media-slider__buffer"></media-slider-buffer>
|
||||
</media-slider-track>
|
||||
<media-slider-thumb class="media-slider__thumb"></media-slider-thumb>
|
||||
<media-slider-preview class="media-slider__preview">
|
||||
<media-slider-value type="pointer" class="media-slider__value media-time"></media-slider-value>
|
||||
</media-slider-preview>
|
||||
</media-time-slider>
|
||||
<media-time type="duration" class="media-time"></media-time>
|
||||
</div>
|
||||
|
||||
@@ -16,10 +16,10 @@ import {
|
||||
playbackRate,
|
||||
popup,
|
||||
poster,
|
||||
preview,
|
||||
root,
|
||||
seek,
|
||||
slider,
|
||||
thumbnail,
|
||||
time,
|
||||
} from '@videojs/skins/minimal/tailwind/video.tailwind';
|
||||
import { createTemplate } from '@videojs/utils/dom';
|
||||
@@ -100,13 +100,16 @@ function getTemplateHTML() {
|
||||
</media-slider-track>
|
||||
<media-slider-thumb class="${cn(slider.thumb.base, slider.thumb.interactive)}"></media-slider-thumb>
|
||||
|
||||
<div class="${preview.root}">
|
||||
<div class="${preview.thumbnailWrapper}">
|
||||
<media-slider-thumbnail class="${preview.thumbnail}"></media-slider-thumbnail>
|
||||
<div class="${thumbnail.root}">
|
||||
<div class="${thumbnail.imageWrapper}">
|
||||
<media-slider-thumbnail class="${thumbnail.image}"></media-slider-thumbnail>
|
||||
</div>
|
||||
<media-slider-value type="pointer" class="${preview.time}"></media-slider-value>
|
||||
${renderIcon('spinner', { class: cn(icon, preview.spinner) })}
|
||||
<media-slider-value type="pointer" class="${cn(time.current, thumbnail.time)}"></media-slider-value>
|
||||
${renderIcon('spinner', { class: cn(icon, thumbnail.spinner) })}
|
||||
</div>
|
||||
<media-slider-preview class="${slider.preview}">
|
||||
<media-slider-value type="pointer" class="${cn(slider.value, time.current)}"></media-slider-value>
|
||||
</media-slider-preview>
|
||||
</media-time-slider>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -77,13 +77,17 @@ function getTemplateHTML() {
|
||||
</media-slider-track>
|
||||
<media-slider-thumb class="media-slider__thumb"></media-slider-thumb>
|
||||
|
||||
<div class="media-preview media-slider__preview">
|
||||
<div class="media-preview__thumbnail-wrapper">
|
||||
<media-slider-thumbnail class="media-preview__thumbnail"></media-slider-thumbnail>
|
||||
<div class="media-thumbnail media-slider__thumbnail">
|
||||
<div class="media-thumbnail__image-wrapper">
|
||||
<media-slider-thumbnail class="media-thumbnail__image"></media-slider-thumbnail>
|
||||
</div>
|
||||
<media-slider-value type="pointer" class="media-time media-preview__time"></media-slider-value>
|
||||
${renderIcon('spinner', { class: 'media-preview__spinner media-icon' })}
|
||||
<media-slider-value type="pointer" class="media-time media-thumbnail__time"></media-slider-value>
|
||||
${renderIcon('spinner', { class: 'media-thumbnail__spinner media-icon' })}
|
||||
</div>
|
||||
|
||||
<media-slider-preview class="media-slider__preview">
|
||||
<media-slider-value type="pointer" class="media-slider__value media-time"></media-slider-value>
|
||||
</media-slider-preview>
|
||||
</media-time-slider>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@ import {
|
||||
playbackRate,
|
||||
popup,
|
||||
poster,
|
||||
preview,
|
||||
root,
|
||||
seek,
|
||||
slider,
|
||||
thumbnail,
|
||||
time,
|
||||
} from '@videojs/skins/default/tailwind/video.tailwind';
|
||||
import { createTemplate } from '@videojs/utils/dom';
|
||||
@@ -97,11 +97,14 @@ function getTemplateHTML() {
|
||||
</media-slider-track>
|
||||
<media-slider-thumb class="${cn(slider.thumb.base, slider.thumb.interactive)}"></media-slider-thumb>
|
||||
|
||||
<div class="${preview.root}">
|
||||
<media-slider-thumbnail class="${preview.thumbnail}"></media-slider-thumbnail>
|
||||
<media-slider-value type="pointer" class="${preview.time}"></media-slider-value>
|
||||
${renderIcon('spinner', { class: cn(icon, preview.spinner) })}
|
||||
<div class="${thumbnail.root}">
|
||||
<media-slider-thumbnail class="${thumbnail.image}"></media-slider-thumbnail>
|
||||
<media-slider-value type="pointer" class="${cn(time.current, thumbnail.time)}"></media-slider-value>
|
||||
${renderIcon('spinner', { class: cn(icon, thumbnail.spinner) })}
|
||||
</div>
|
||||
<media-slider-preview class="${slider.preview}">
|
||||
<media-slider-value type="pointer" class="${cn(slider.value, time.current)}"></media-slider-value>
|
||||
</media-slider-preview>
|
||||
</media-time-slider>
|
||||
<media-time type="duration" class="${time.duration}"></media-time>
|
||||
</div>
|
||||
|
||||
@@ -74,11 +74,15 @@ function getTemplateHTML() {
|
||||
</media-slider-track>
|
||||
<media-slider-thumb class="media-slider__thumb"></media-slider-thumb>
|
||||
|
||||
<div class="media-surface media-preview media-slider__preview">
|
||||
<media-slider-thumbnail class="media-preview__thumbnail"></media-slider-thumbnail>
|
||||
<media-slider-value type="pointer" class="media-time media-preview__time"></media-slider-value>
|
||||
${renderIcon('spinner', { class: 'media-preview__spinner media-icon' })}
|
||||
<div class="media-surface media-thumbnail media-slider__thumbnail">
|
||||
<media-slider-thumbnail class="media-thumbnail__image"></media-slider-thumbnail>
|
||||
<media-slider-value type="pointer" class="media-time media-thumbnail__time"></media-slider-value>
|
||||
${renderIcon('spinner', { class: 'media-thumbnail__spinner media-icon' })}
|
||||
</div>
|
||||
|
||||
<media-slider-preview class="media-slider__preview">
|
||||
<media-slider-value type="pointer" class="media-slider__value media-time"></media-slider-value>
|
||||
</media-slider-preview>
|
||||
</media-time-slider>
|
||||
<media-time type="duration" class="media-time"></media-time>
|
||||
</div>
|
||||
|
||||
@@ -187,7 +187,7 @@ export function MinimalAudioSkinTailwind(props: MinimalAudioSkinProps): ReactNod
|
||||
</SeekButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}>Seek backward {SEEK_TIME} seconds</Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
|
||||
<Tooltip.Root side="top" boundary="viewport">
|
||||
@@ -201,7 +201,7 @@ export function MinimalAudioSkinTailwind(props: MinimalAudioSkinProps): ReactNod
|
||||
</SeekButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}>Seek forward {SEEK_TIME} seconds</Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
</div>
|
||||
|
||||
@@ -218,6 +218,9 @@ export function MinimalAudioSkinTailwind(props: MinimalAudioSkinProps): ReactNod
|
||||
<TimeSlider.Buffer render={<SliderBuffer />} />
|
||||
</TimeSlider.Track>
|
||||
<TimeSlider.Thumb render={<SliderThumb />} />
|
||||
<TimeSlider.Preview className={slider.preview}>
|
||||
<TimeSlider.Value type="pointer" className={slider.value} />
|
||||
</TimeSlider.Preview>
|
||||
</TimeSlider.Root>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ export function MinimalAudioSkin(props: MinimalAudioSkinProps): ReactNode {
|
||||
</SeekButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className="media-tooltip">Seek backward {SEEK_TIME} seconds</Tooltip.Popup>
|
||||
<Tooltip.Popup className="media-tooltip" />
|
||||
</Tooltip.Root>
|
||||
|
||||
<Tooltip.Root side="top" boundary="viewport">
|
||||
@@ -148,7 +148,7 @@ export function MinimalAudioSkin(props: MinimalAudioSkinProps): ReactNode {
|
||||
</SeekButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className="media-tooltip">Seek forward {SEEK_TIME} seconds</Tooltip.Popup>
|
||||
<Tooltip.Popup className="media-tooltip" />
|
||||
</Tooltip.Root>
|
||||
</div>
|
||||
|
||||
@@ -165,6 +165,9 @@ export function MinimalAudioSkin(props: MinimalAudioSkinProps): ReactNode {
|
||||
<TimeSlider.Buffer className="media-slider__buffer" />
|
||||
</TimeSlider.Track>
|
||||
<TimeSlider.Thumb className="media-slider__thumb" />
|
||||
<TimeSlider.Preview className="media-slider__preview">
|
||||
<TimeSlider.Value type="pointer" className="media-slider__value media-time" />
|
||||
</TimeSlider.Preview>
|
||||
</TimeSlider.Root>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ export function AudioSkinTailwind(props: AudioSkinProps): ReactNode {
|
||||
</SeekButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}>Seek backward {SEEK_TIME} seconds</Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
|
||||
<Tooltip.Root side="top" boundary="viewport">
|
||||
@@ -203,7 +203,7 @@ export function AudioSkinTailwind(props: AudioSkinProps): ReactNode {
|
||||
</SeekButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}>Seek forward {SEEK_TIME} seconds</Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
</div>
|
||||
|
||||
@@ -215,6 +215,9 @@ export function AudioSkinTailwind(props: AudioSkinProps): ReactNode {
|
||||
<TimeSlider.Buffer render={<SliderBuffer />} />
|
||||
</TimeSlider.Track>
|
||||
<TimeSlider.Thumb render={<SliderThumb />} />
|
||||
<TimeSlider.Preview className={slider.preview}>
|
||||
<TimeSlider.Value type="pointer" className={slider.value} />
|
||||
</TimeSlider.Preview>
|
||||
</TimeSlider.Root>
|
||||
<Time.Value type="duration" className={time.duration} />
|
||||
</div>
|
||||
|
||||
@@ -134,7 +134,7 @@ export function AudioSkin(props: AudioSkinProps): ReactNode {
|
||||
</SeekButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className="media-surface media-tooltip">Seek backward {SEEK_TIME} seconds</Tooltip.Popup>
|
||||
<Tooltip.Popup className="media-surface media-tooltip" />
|
||||
</Tooltip.Root>
|
||||
|
||||
<Tooltip.Root side="top" boundary="viewport">
|
||||
@@ -148,7 +148,7 @@ export function AudioSkin(props: AudioSkinProps): ReactNode {
|
||||
</SeekButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className="media-surface media-tooltip">Seek forward {SEEK_TIME} seconds</Tooltip.Popup>
|
||||
<Tooltip.Popup className="media-surface media-tooltip" />
|
||||
</Tooltip.Root>
|
||||
</div>
|
||||
|
||||
@@ -160,6 +160,9 @@ export function AudioSkin(props: AudioSkinProps): ReactNode {
|
||||
<TimeSlider.Buffer className="media-slider__buffer" />
|
||||
</TimeSlider.Track>
|
||||
<TimeSlider.Thumb className="media-slider__thumb" />
|
||||
<TimeSlider.Preview className="media-slider__preview">
|
||||
<TimeSlider.Value type="pointer" className="media-slider__value media-time" />
|
||||
</TimeSlider.Preview>
|
||||
</TimeSlider.Root>
|
||||
<Time.Value type="duration" className="media-time" />
|
||||
</div>
|
||||
|
||||
@@ -129,7 +129,7 @@ export function MinimalLiveAudioSkinTailwind(props: MinimalLiveAudioSkinProps):
|
||||
</PlayButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
|
||||
<LiveButton className={cn(button.base, button.subtle, button.live)} />
|
||||
|
||||
@@ -129,7 +129,7 @@ export function LiveAudioSkinTailwind(props: LiveAudioSkinProps): ReactNode {
|
||||
</PlayButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
|
||||
<LiveButton className={cn(button.base, button.subtle, button.live)} />
|
||||
|
||||
@@ -187,7 +187,7 @@ export function MinimalLiveVideoSkinTailwind(props: MinimalLiveVideoSkinProps):
|
||||
</PlayButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
|
||||
<LiveButton className={cn(button.base, button.subtle, button.live)} />
|
||||
@@ -207,7 +207,7 @@ export function MinimalLiveVideoSkinTailwind(props: MinimalLiveVideoSkinProps):
|
||||
</CaptionsButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
|
||||
<Tooltip.Root side="top">
|
||||
@@ -219,7 +219,7 @@ export function MinimalLiveVideoSkinTailwind(props: MinimalLiveVideoSkinProps):
|
||||
</CastButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
|
||||
<Tooltip.Root side="top">
|
||||
@@ -243,7 +243,7 @@ export function MinimalLiveVideoSkinTailwind(props: MinimalLiveVideoSkinProps):
|
||||
</PiPButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
|
||||
<Tooltip.Root side="top">
|
||||
@@ -255,7 +255,7 @@ export function MinimalLiveVideoSkinTailwind(props: MinimalLiveVideoSkinProps):
|
||||
</FullscreenButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
</div>
|
||||
</Tooltip.Provider>
|
||||
|
||||
@@ -189,7 +189,7 @@ export function LiveVideoSkinTailwind(props: LiveVideoSkinProps): ReactNode {
|
||||
</PlayButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
|
||||
<LiveButton className={cn(button.base, button.subtle, button.live)} />
|
||||
@@ -209,7 +209,7 @@ export function LiveVideoSkinTailwind(props: LiveVideoSkinProps): ReactNode {
|
||||
</CaptionsButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
|
||||
<Tooltip.Root side="top">
|
||||
@@ -221,7 +221,7 @@ export function LiveVideoSkinTailwind(props: LiveVideoSkinProps): ReactNode {
|
||||
</CastButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
|
||||
<Tooltip.Root side="top">
|
||||
@@ -245,7 +245,7 @@ export function LiveVideoSkinTailwind(props: LiveVideoSkinProps): ReactNode {
|
||||
</PiPButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
|
||||
<Tooltip.Root side="top">
|
||||
@@ -257,7 +257,7 @@ export function LiveVideoSkinTailwind(props: LiveVideoSkinProps): ReactNode {
|
||||
</FullscreenButton>
|
||||
}
|
||||
/>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)}></Tooltip.Popup>
|
||||
<Tooltip.Popup className={cn(popup.tooltip)} />
|
||||
</Tooltip.Root>
|
||||
</div>
|
||||
</Tooltip.Provider>
|
||||
|
||||
@@ -15,10 +15,10 @@ import {
|
||||
playbackRate,
|
||||
popup,
|
||||
poster,
|
||||
preview,
|
||||
root,
|
||||
seek,
|
||||
slider,
|
||||
thumbnail,
|
||||
time,
|
||||
} from '@videojs/skins/minimal/tailwind/video.tailwind';
|
||||
import { isString } from '@videojs/utils/predicate';
|
||||
@@ -274,13 +274,16 @@ export function MinimalVideoSkinTailwind(props: MinimalVideoSkinProps): ReactNod
|
||||
<TimeSlider.Buffer render={<SliderBuffer />} />
|
||||
</TimeSlider.Track>
|
||||
<TimeSlider.Thumb render={<SliderThumb />} />
|
||||
<div className={preview.root}>
|
||||
<div className={preview.thumbnailWrapper}>
|
||||
<Slider.Thumbnail className={preview.thumbnail} />
|
||||
<div className={thumbnail.root}>
|
||||
<div className={thumbnail.imageWrapper}>
|
||||
<Slider.Thumbnail className={thumbnail.image} />
|
||||
</div>
|
||||
<TimeSlider.Value type="pointer" className={preview.time} />
|
||||
<SpinnerIcon className={cn(icon, preview.spinner)} />
|
||||
<TimeSlider.Value type="pointer" className={cn(time.current, thumbnail.time)} />
|
||||
<SpinnerIcon className={cn(icon, thumbnail.spinner)} />
|
||||
</div>
|
||||
<TimeSlider.Preview className={slider.preview}>
|
||||
<TimeSlider.Value type="pointer" className={cn(slider.value, time.current)} />
|
||||
</TimeSlider.Preview>
|
||||
</TimeSlider.Root>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -207,13 +207,17 @@ export function MinimalVideoSkin(props: MinimalVideoSkinProps): ReactNode {
|
||||
</TimeSlider.Track>
|
||||
<TimeSlider.Thumb className="media-slider__thumb" />
|
||||
|
||||
<div className="media-preview media-slider__preview">
|
||||
<div className="media-preview__thumbnail-wrapper">
|
||||
<Slider.Thumbnail className="media-preview__thumbnail" />
|
||||
<div className="media-thumbnail media-slider__thumbnail">
|
||||
<div className="media-thumbnail__image-wrapper">
|
||||
<Slider.Thumbnail className="media-thumbnail__image" />
|
||||
</div>
|
||||
<TimeSlider.Value type="pointer" className="media-time media-preview__time" />
|
||||
<SpinnerIcon className="media-preview__spinner media-icon" />
|
||||
<TimeSlider.Value type="pointer" className="media-time media-thumbnail__time" />
|
||||
<SpinnerIcon className="media-thumbnail__spinner media-icon" />
|
||||
</div>
|
||||
|
||||
<TimeSlider.Preview className="media-slider__preview">
|
||||
<TimeSlider.Value type="pointer" className="media-slider__value media-time" />
|
||||
</TimeSlider.Preview>
|
||||
</TimeSlider.Root>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@ import {
|
||||
playbackRate,
|
||||
popup,
|
||||
poster,
|
||||
preview,
|
||||
root,
|
||||
seek,
|
||||
slider,
|
||||
thumbnail,
|
||||
time,
|
||||
} from '@videojs/skins/default/tailwind/video.tailwind';
|
||||
import { isString } from '@videojs/utils/predicate';
|
||||
@@ -271,11 +271,14 @@ export function VideoSkinTailwind(props: VideoSkinProps): ReactNode {
|
||||
<TimeSlider.Buffer render={<SliderBuffer />} />
|
||||
</TimeSlider.Track>
|
||||
<TimeSlider.Thumb render={<SliderThumb />} />
|
||||
<div className={preview.root}>
|
||||
<Slider.Thumbnail className={preview.thumbnail} />
|
||||
<TimeSlider.Value type="pointer" className={preview.time} />
|
||||
<SpinnerIcon className={cn(icon, preview.spinner)} />
|
||||
<div className={thumbnail.root}>
|
||||
<Slider.Thumbnail className={thumbnail.image} />
|
||||
<TimeSlider.Value type="pointer" className={cn(time.current, thumbnail.time)} />
|
||||
<SpinnerIcon className={cn(icon, thumbnail.spinner)} />
|
||||
</div>
|
||||
<TimeSlider.Preview className={slider.preview}>
|
||||
<TimeSlider.Value type="pointer" className={cn(slider.value, time.current)} />
|
||||
</TimeSlider.Preview>
|
||||
</TimeSlider.Root>
|
||||
<Time.Value type="duration" className={time.duration} />
|
||||
</div>
|
||||
|
||||
@@ -204,11 +204,15 @@ export function VideoSkin(props: VideoSkinProps): ReactNode {
|
||||
</TimeSlider.Track>
|
||||
<TimeSlider.Thumb className="media-slider__thumb" />
|
||||
|
||||
<div className="media-surface media-preview media-slider__preview">
|
||||
<Slider.Thumbnail className="media-preview__thumbnail" />
|
||||
<TimeSlider.Value type="pointer" className="media-time media-preview__time" />
|
||||
<SpinnerIcon className="media-preview__spinner media-icon" />
|
||||
<div className="media-surface media-thumbnail media-slider__thumbnail">
|
||||
<Slider.Thumbnail className="media-thumbnail__image" />
|
||||
<TimeSlider.Value type="pointer" className="media-time media-thumbnail__time" />
|
||||
<SpinnerIcon className="media-thumbnail__spinner media-icon" />
|
||||
</div>
|
||||
|
||||
<TimeSlider.Preview className="media-slider__preview">
|
||||
<TimeSlider.Value type="pointer" className="media-slider__value media-time" />
|
||||
</TimeSlider.Preview>
|
||||
</TimeSlider.Root>
|
||||
<Time.Value type="duration" className="media-time" />
|
||||
</div>
|
||||
|
||||
@@ -55,9 +55,9 @@
|
||||
background-color: currentColor;
|
||||
border-radius: calc(infinity * 1px);
|
||||
box-shadow:
|
||||
0 0 0 1px var(--media-current-shadow-color-subtle, oklch(0 0 0 / 0.1)),
|
||||
0 1px 3px 0 oklch(0 0 0 / 0.15),
|
||||
0 1px 2px -1px oklch(0 0 0 / 0.15);
|
||||
0 0 0 1px var(--media-current-shadow-color, oklch(0 0 0 / 0.1)),
|
||||
0 1px 3px 0 oklch(0 0 0 / 0.35),
|
||||
0 1px 2px -1px oklch(0 0 0 / 0.35);
|
||||
opacity: 0;
|
||||
translate: -50% -50%;
|
||||
transition-timing-function: ease-out;
|
||||
@@ -76,7 +76,7 @@
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
outline-color: oklch(from currentColor l c h / 0.25);
|
||||
outline-color: oklch(from currentColor l c h / 0.15);
|
||||
outline-offset: 0;
|
||||
}
|
||||
|
||||
@@ -109,6 +109,49 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Preview */
|
||||
.media-default-skin .media-slider__preview {
|
||||
& .media-slider__value,
|
||||
&::before {
|
||||
opacity: 0;
|
||||
scale: 0.5;
|
||||
transition-timing-function: ease-out;
|
||||
transition-duration: 200ms;
|
||||
transition-property: opacity, scale;
|
||||
}
|
||||
|
||||
& .media-slider__value {
|
||||
position: absolute;
|
||||
bottom: 2.25rem;
|
||||
text-shadow: 0 1px 0 var(--media-current-shadow-color);
|
||||
filter: blur(8px);
|
||||
translate: -50% 0.5rem;
|
||||
transition-property: filter, opacity, scale, translate;
|
||||
}
|
||||
|
||||
&::before {
|
||||
display: block;
|
||||
min-width: 0.25rem;
|
||||
height: 0.25rem;
|
||||
content: "";
|
||||
background-color: currentColor;
|
||||
border-radius: 100%;
|
||||
box-shadow:
|
||||
0 0 0 1px var(--media-current-shadow-color, oklch(0 0 0 / 0.15)),
|
||||
0 1px 2px 0 oklch(0 0 0 / 0.35);
|
||||
}
|
||||
|
||||
&[data-pointing] .media-slider__value,
|
||||
&[data-pointing]:not([data-dragging])::before {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
}
|
||||
&[data-pointing] .media-slider__value {
|
||||
filter: blur(0);
|
||||
translate: -50% 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Shared track fills */
|
||||
.media-default-skin .media-slider__buffer,
|
||||
.media-default-skin .media-slider__fill {
|
||||
|
||||
+13
-16
@@ -1,12 +1,13 @@
|
||||
/* ==========================================================================
|
||||
Media preview
|
||||
Media thumbnail
|
||||
========================================================================== */
|
||||
.media-default-skin .media-preview {
|
||||
|
||||
.media-default-skin .media-thumbnail {
|
||||
pointer-events: none;
|
||||
background-color: oklch(0 0 0 / 0.9);
|
||||
border-radius: 0.75rem;
|
||||
|
||||
& .media-preview__thumbnail {
|
||||
& .media-thumbnail__image {
|
||||
position: relative;
|
||||
display: block;
|
||||
overflow: clip;
|
||||
@@ -21,18 +22,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
& .media-preview__time {
|
||||
& .media-thumbnail__time {
|
||||
position: absolute;
|
||||
inset-inline: 0;
|
||||
bottom: 0.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
& .media-overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
& .media-preview__spinner {
|
||||
& .media-thumbnail__spinner {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
@@ -40,22 +37,22 @@
|
||||
translate: -50% -50%;
|
||||
}
|
||||
|
||||
& .media-preview__thumbnail,
|
||||
& .media-preview__spinner {
|
||||
& .media-thumbnail__image,
|
||||
& .media-thumbnail__spinner {
|
||||
transition: opacity 150ms ease-out;
|
||||
}
|
||||
|
||||
&:not(:has(.media-preview__thumbnail[data-loading])) {
|
||||
& .media-preview__spinner {
|
||||
&:not(:has(.media-thumbnail__image[data-loading])) {
|
||||
& .media-thumbnail__spinner {
|
||||
--media-spinner-animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:has(.media-preview__thumbnail[data-loading]) {
|
||||
& .media-preview__thumbnail {
|
||||
&:has(.media-thumbnail__image[data-loading]) {
|
||||
& .media-thumbnail__image {
|
||||
opacity: 0;
|
||||
}
|
||||
& .media-preview__spinner {
|
||||
& .media-thumbnail__spinner {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
@import "./components/icons.css";
|
||||
@import "./components/menus.css";
|
||||
@import "./components/poster.css";
|
||||
@import "./components/preview.css";
|
||||
@import "./components/thumbnail.css";
|
||||
@import "./components/slider.css";
|
||||
@import "./components/popup.css";
|
||||
@import "./components/captions.css";
|
||||
@@ -245,21 +245,32 @@
|
||||
box-shadow: 0 0 0 1px oklch(0 0 0 / 0.05);
|
||||
}
|
||||
|
||||
.media-default-skin--video .media-slider__preview {
|
||||
--media-preview-max-width: 11rem;
|
||||
--media-preview-padding: -1.125rem;
|
||||
.media-default-skin--video .media-slider__thumbnail {
|
||||
--media-slider-thumbnail-max-width: 11rem;
|
||||
--media-slider-thumbnail-padding: -1.125rem;
|
||||
/**
|
||||
Inset is the difference between the container width and the slider (100%) width.
|
||||
Divided by 2 as we render the time on both sides.
|
||||
*/
|
||||
--media-preview-inset: calc((100cqi - 100%) / 2);
|
||||
--media-slider-thumbnail-inset: calc((100cqi - 100%) / 2);
|
||||
|
||||
position: absolute;
|
||||
bottom: calc(100% + 1.2rem);
|
||||
left: clamp(
|
||||
calc(var(--media-preview-max-width) / 2 + var(--media-preview-padding) - var(--media-preview-inset)),
|
||||
calc(
|
||||
var(--media-slider-thumbnail-max-width) /
|
||||
2 +
|
||||
var(--media-slider-thumbnail-padding) -
|
||||
var(--media-slider-thumbnail-inset)
|
||||
),
|
||||
var(--media-slider-pointer),
|
||||
calc(100% - var(--media-preview-max-width) / 2 - var(--media-preview-padding) + var(--media-preview-inset))
|
||||
calc(
|
||||
100% -
|
||||
var(--media-slider-thumbnail-max-width) /
|
||||
2 -
|
||||
var(--media-slider-thumbnail-padding) +
|
||||
var(--media-slider-thumbnail-inset)
|
||||
)
|
||||
);
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
@@ -271,16 +282,22 @@
|
||||
transition-duration: 150ms;
|
||||
transition-property: scale, opacity, filter;
|
||||
|
||||
& .media-preview__thumbnail {
|
||||
max-width: var(--media-preview-max-width);
|
||||
& .media-thumbnail__image {
|
||||
max-width: var(--media-slider-thumbnail-max-width);
|
||||
}
|
||||
|
||||
&:has(.media-preview__thumbnail[data-loading]) {
|
||||
&:has(.media-thumbnail__image[data-loading]) {
|
||||
max-height: 6rem;
|
||||
}
|
||||
}
|
||||
.media-default-skin--video .media-slider[data-pointing] .media-slider__preview:has([role="img"]:not([data-hidden])) {
|
||||
.media-default-skin--video .media-slider[data-pointing] .media-slider__thumbnail:has([role="img"]:not([data-hidden])) {
|
||||
opacity: 1;
|
||||
filter: blur(0);
|
||||
scale: 1;
|
||||
}
|
||||
.media-default-skin--video
|
||||
.media-slider__thumbnail:has([role="img"]:not([data-hidden]))
|
||||
+ .media-slider__preview
|
||||
.media-slider__value {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -40,11 +40,11 @@ export const slider = {
|
||||
base: cn(
|
||||
'z-10 absolute -translate-x-1/2 -translate-y-1/2',
|
||||
'bg-current rounded-full',
|
||||
'shadow-[0_0_0_1px_var(--media-current-shadow-color-subtle,oklch(0_0_0/0.1)),0_1px_3px_0_oklch(0_0_0/0.15),0_1px_2px_-1px_oklch(0_0_0/0.15)]',
|
||||
'shadow-[0_0_0_1px_var(--media-current-shadow-color,oklch(0_0_0/0.1)),0_1px_3px_0_oklch(0_0_0/0.35),0_1px_2px_-1px_oklch(0_0_0/0.35)]',
|
||||
'transition-[opacity,height,width,outline-offset] duration-150 ease-out select-none',
|
||||
'outline-4 outline-transparent -outline-offset-4',
|
||||
'hover:outline-current/25 hover:outline-offset-0',
|
||||
'focus-visible:outline-current/25 focus-visible:outline-offset-0',
|
||||
'hover:outline-current/15 hover:outline-offset-0',
|
||||
'focus-visible:outline-current/15 focus-visible:outline-offset-0',
|
||||
// Horizontal
|
||||
'data-[orientation=horizontal]:top-1/2 data-[orientation=horizontal]:left-(--media-slider-fill)',
|
||||
// Vertical
|
||||
@@ -57,4 +57,20 @@ export const slider = {
|
||||
'group-active/slider:size-3'
|
||||
),
|
||||
},
|
||||
preview: cn(
|
||||
'group/preview',
|
||||
'before:block before:min-w-1 before:h-1 before:bg-current before:rounded-full before:opacity-0 before:scale-50',
|
||||
'before:shadow-[0_0_0_1px_var(--media-current-shadow-color,oklch(0_0_0/0.15)),0_1px_2px_0_oklch(0_0_0/0.35)]',
|
||||
'before:transition-[opacity,scale] before:duration-200 before:ease-out',
|
||||
'data-pointing:not-data-dragging:before:opacity-100 data-pointing:not-data-dragging:before:scale-100',
|
||||
'peer-has-[[role=img]:not([data-hidden])]/thumbnail:*:hidden'
|
||||
),
|
||||
value: cn(
|
||||
'absolute bottom-9 tabular-nums',
|
||||
'-translate-x-1/2 translate-y-2 scale-50 opacity-0 blur-lg',
|
||||
'text-shadow-2xs text-shadow-(color:--media-current-shadow-color)',
|
||||
'transition-[filter,opacity,scale,translate] duration-200 ease-out',
|
||||
'group-data-pointing/preview:translate-y-0 group-data-pointing/preview:scale-100',
|
||||
'group-data-pointing/preview:opacity-100 group-data-pointing/preview:blur-none'
|
||||
),
|
||||
};
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
import { cn } from '@videojs/utils/style';
|
||||
|
||||
export const preview = {
|
||||
root: cn('group/preview pointer-events-none bg-black/90 rounded-xl'),
|
||||
thumbnail: cn(
|
||||
export const thumbnail = {
|
||||
root: cn('group/thumbnail peer/thumbnail pointer-events-none bg-black/90 rounded-xl'),
|
||||
image: cn(
|
||||
'block relative overflow-clip rounded-[inherit]',
|
||||
'transition-opacity duration-150 ease-out',
|
||||
'after:absolute after:inset-0 after:rounded-[inherit]',
|
||||
@@ -13,6 +13,6 @@ export const preview = {
|
||||
spinner: cn(
|
||||
'absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-0',
|
||||
'transition-opacity duration-150 ease-out',
|
||||
'group-not-has-[[role=img][data-loading]]/preview:[--media-spinner-animation:none] group-has-[[role=img][data-loading]]/preview:opacity-100'
|
||||
'group-not-has-[[role=img][data-loading]]/thumbnail:[--media-spinner-animation:none] group-has-[[role=img][data-loading]]/thumbnail:opacity-100'
|
||||
),
|
||||
};
|
||||
@@ -5,10 +5,10 @@ import { controls as baseControls } from './components/controls';
|
||||
import { error as baseError } from './components/error';
|
||||
import { inputFeedback as baseInputFeedback } from './components/input-feedback';
|
||||
import { popup as basePopup } from './components/popup';
|
||||
import { preview as basePreview } from './components/preview';
|
||||
import { root as baseRoot } from './components/root';
|
||||
import { slider as baseSlider } from './components/slider';
|
||||
import { surface } from './components/surface';
|
||||
import { thumbnail as baseThumbnail } from './components/thumbnail';
|
||||
import { time as baseTime } from './components/time';
|
||||
|
||||
/* ==========================================================================
|
||||
@@ -133,23 +133,24 @@ export const time = {
|
||||
};
|
||||
|
||||
/* ==========================================================================
|
||||
Preview (with video surface)
|
||||
Thumbnail (with video surface)
|
||||
========================================================================== */
|
||||
|
||||
export const preview = {
|
||||
...basePreview,
|
||||
export const thumbnail = {
|
||||
...baseThumbnail,
|
||||
root: cn(
|
||||
'[--media-preview-max-width:11rem] [--media-preview-padding:-1.125rem] [--media-preview-inset:calc((100cqi-100%)/2)]',
|
||||
'absolute [left:clamp(calc(var(--media-preview-max-width)/2+var(--media-preview-padding)-var(--media-preview-inset)),var(--media-slider-pointer),calc(100%-var(--media-preview-max-width)/2-var(--media-preview-padding)+var(--media-preview-inset)))] bottom-[calc(100%+1.2rem)] -translate-x-1/2',
|
||||
baseThumbnail.root,
|
||||
surface,
|
||||
'[--media-slider-thumbnail-max-width:11rem] [--media-slider-thumbnail-padding:-1.125rem] [--media-slider-thumbnail-inset:calc((100cqi-100%)/2)]',
|
||||
'absolute [left:clamp(calc(var(--media-slider-thumbnail-max-width)/2+var(--media-slider-thumbnail-padding)-var(--media-slider-thumbnail-inset)),var(--media-slider-pointer),calc(100%-var(--media-slider-thumbnail-max-width)/2-var(--media-slider-thumbnail-padding)+var(--media-slider-thumbnail-inset)))] bottom-[calc(100%+1.2rem)] -translate-x-1/2',
|
||||
'opacity-0 scale-80 blur-sm origin-bottom',
|
||||
'transition-[scale,opacity,filter] duration-150',
|
||||
'group-data-pointing/slider:opacity-100 group-data-pointing/slider:scale-100 group-data-pointing/slider:blur-none',
|
||||
'has-[[role=img][data-hidden]]:opacity-0 has-[[role=img][data-hidden]]:scale-80 has-[[role=img][data-hidden]]:blur-sm',
|
||||
'has-[[role=img][data-loading]]:max-h-24',
|
||||
surface,
|
||||
basePreview.root
|
||||
'has-[[role=img]:not([data-hidden])]:group-data-pointing/slider:opacity-100',
|
||||
'has-[[role=img]:not([data-hidden])]:group-data-pointing/slider:scale-100',
|
||||
'has-[[role=img]:not([data-hidden])]:group-data-pointing/slider:blur-none',
|
||||
'has-[[role=img][data-loading]]:max-h-24'
|
||||
),
|
||||
thumbnail: cn(basePreview.thumbnail, 'max-w-(--media-preview-max-width)'),
|
||||
image: cn(baseThumbnail.image, 'max-w-(--media-slider-thumbnail-max-width)'),
|
||||
};
|
||||
|
||||
/* ==========================================================================
|
||||
|
||||
@@ -112,3 +112,7 @@
|
||||
padding: 0 0 0 4rem;
|
||||
background: linear-gradient(to left, var(--media-controls-background-color) 80%, transparent 100%);
|
||||
}
|
||||
|
||||
.media-minimal-skin--audio .media-slider__preview .media-slider__value {
|
||||
bottom: 2.5rem;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
background-color: currentColor;
|
||||
border-radius: calc(infinity * 1px);
|
||||
box-shadow:
|
||||
0 0 0 1px var(--media-current-shadow-color-subtle, oklch(0 0 0 / 0.1)),
|
||||
0 0 0 1px var(--media-current-shadow-color, oklch(0 0 0 / 0.15)),
|
||||
0 1px 3px 0 oklch(0 0 0 / 0.15),
|
||||
0 1px 2px -1px oklch(0 0 0 / 0.15);
|
||||
opacity: 0;
|
||||
@@ -90,6 +90,53 @@
|
||||
scale: 1;
|
||||
}
|
||||
|
||||
/* Preview */
|
||||
.media-minimal-skin .media-slider__preview {
|
||||
& .media-slider__value,
|
||||
&::before {
|
||||
opacity: 0;
|
||||
scale: 0.5;
|
||||
transition-timing-function: ease-out;
|
||||
transition-duration: 200ms;
|
||||
transition-property: opacity, scale;
|
||||
}
|
||||
|
||||
& .media-slider__value {
|
||||
position: absolute;
|
||||
bottom: 1.5rem;
|
||||
text-shadow: 0 1px 0 var(--media-current-shadow-color);
|
||||
filter: blur(8px);
|
||||
translate: -50% 0.5rem;
|
||||
transition-property: filter, opacity, scale, translate;
|
||||
}
|
||||
|
||||
&::before {
|
||||
display: block;
|
||||
content: "";
|
||||
background-color: oklch(from currentColor l c h / 0.35);
|
||||
}
|
||||
|
||||
&[data-pointing] .media-slider__value,
|
||||
&[data-pointing]:not([data-dragging])::before {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
}
|
||||
&[data-pointing] .media-slider__value {
|
||||
filter: blur(0);
|
||||
translate: -50% 0;
|
||||
}
|
||||
|
||||
&[data-orientation="horizontal"]::before {
|
||||
min-width: 1px;
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
&[data-orientation="vertical"]::before {
|
||||
width: 1.25rem;
|
||||
min-height: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Shared track fills */
|
||||
.media-minimal-skin .media-slider__buffer,
|
||||
.media-minimal-skin .media-slider__fill {
|
||||
|
||||
+14
-13
@@ -1,20 +1,21 @@
|
||||
/* ==========================================================================
|
||||
Media preview
|
||||
Media thumbnail
|
||||
========================================================================== */
|
||||
.media-minimal-skin .media-preview {
|
||||
|
||||
.media-minimal-skin .media-thumbnail {
|
||||
pointer-events: none;
|
||||
|
||||
& .media-preview__thumbnail-wrapper {
|
||||
& .media-thumbnail__image-wrapper {
|
||||
position: relative;
|
||||
background-color: oklch(0 0 0 / 0.9);
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
& .media-preview__thumbnail {
|
||||
& .media-thumbnail__image {
|
||||
display: block;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
& .media-preview__time {
|
||||
& .media-thumbnail__time {
|
||||
display: block;
|
||||
margin-top: 0.5rem;
|
||||
text-align: center;
|
||||
@@ -24,7 +25,7 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
& .media-preview__spinner {
|
||||
& .media-thumbnail__spinner {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
@@ -32,22 +33,22 @@
|
||||
translate: -50% -50%;
|
||||
}
|
||||
|
||||
& .media-preview__thumbnail,
|
||||
& .media-preview__spinner {
|
||||
& .media-thumbnail__image,
|
||||
& .media-thumbnail__spinner {
|
||||
transition: opacity 150ms ease-out;
|
||||
}
|
||||
|
||||
&:not(:has(.media-preview__thumbnail[data-loading])) {
|
||||
& .media-preview__spinner {
|
||||
&:not(:has(.media-thumbnail__image[data-loading])) {
|
||||
& .media-thumbnail__spinner {
|
||||
--media-spinner-animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:has(.media-preview__thumbnail[data-loading]) {
|
||||
& .media-preview__thumbnail {
|
||||
&:has(.media-thumbnail__image[data-loading]) {
|
||||
& .media-thumbnail__image {
|
||||
opacity: 0;
|
||||
}
|
||||
& .media-preview__spinner {
|
||||
& .media-thumbnail__spinner {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
@import "./components/button-group.css";
|
||||
@import "./components/icons.css";
|
||||
@import "./components/poster.css";
|
||||
@import "./components/preview.css";
|
||||
@import "./components/thumbnail.css";
|
||||
@import "./components/slider.css";
|
||||
@import "./components/popup.css";
|
||||
@import "./components/menus.css";
|
||||
@@ -261,21 +261,27 @@
|
||||
Slider preview
|
||||
========================================================================== */
|
||||
|
||||
.media-minimal-skin--video .media-slider__preview {
|
||||
--media-preview-max-width: 11rem;
|
||||
--media-preview-padding: -0.5rem;
|
||||
.media-minimal-skin--video .media-slider__thumbnail {
|
||||
--media-slider-thumbnail-max-width: 11rem;
|
||||
--media-slider-thumbnail-padding: -0.5rem;
|
||||
/**
|
||||
Inset is the difference between the container width and the slider (100%) width.
|
||||
We only add to the end as we render the time there.
|
||||
*/
|
||||
--media-preview-inset: calc(100cqi - 100%);
|
||||
--media-slider-thumbnail-inset: calc(100cqi - 100%);
|
||||
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
left: clamp(
|
||||
calc(var(--media-preview-max-width) / 2 + var(--media-preview-padding)),
|
||||
calc(var(--media-slider-thumbnail-max-width) / 2 + var(--media-slider-thumbnail-padding)),
|
||||
var(--media-slider-pointer),
|
||||
calc(100% - var(--media-preview-max-width) / 2 - var(--media-preview-padding) + var(--media-preview-inset))
|
||||
calc(
|
||||
100% -
|
||||
var(--media-slider-thumbnail-max-width) /
|
||||
2 -
|
||||
var(--media-slider-thumbnail-padding) +
|
||||
var(--media-slider-thumbnail-inset)
|
||||
)
|
||||
);
|
||||
opacity: 0;
|
||||
filter: blur(8px);
|
||||
@@ -287,11 +293,10 @@
|
||||
transition-property: scale, opacity, filter;
|
||||
|
||||
@container media-root (width > 42rem) {
|
||||
bottom: calc(100% + 0.25rem);
|
||||
left: var(--media-slider-pointer);
|
||||
}
|
||||
|
||||
& .media-preview__thumbnail-wrapper {
|
||||
& .media-thumbnail__image-wrapper {
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
@@ -306,16 +311,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
& .media-preview__thumbnail {
|
||||
max-width: var(--media-preview-max-width);
|
||||
& .media-thumbnail__image {
|
||||
max-width: var(--media-slider-thumbnail-max-width);
|
||||
}
|
||||
|
||||
&:has(.media-preview__thumbnail[data-loading]) {
|
||||
&:has(.media-thumbnail__image[data-loading]) {
|
||||
max-height: 6rem;
|
||||
}
|
||||
}
|
||||
.media-minimal-skin--video .media-slider[data-pointing] .media-slider__preview:has([role="img"]:not([data-hidden])) {
|
||||
.media-minimal-skin--video .media-slider[data-pointing] .media-slider__thumbnail:has([role="img"]:not([data-hidden])) {
|
||||
opacity: 1;
|
||||
filter: blur(0);
|
||||
scale: 1;
|
||||
}
|
||||
.media-minimal-skin--video
|
||||
.media-slider__thumbnail:has([role="img"]:not([data-hidden]))
|
||||
+ .media-slider__preview
|
||||
.media-slider__value {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { controls as baseControls } from './components/controls';
|
||||
import { error as baseError } from './components/error';
|
||||
import { popup as basePopup } from './components/popup';
|
||||
import { root as baseRoot } from './components/root';
|
||||
import { slider as baseSlider } from './components/slider';
|
||||
|
||||
/* ==========================================================================
|
||||
Root
|
||||
@@ -67,6 +68,15 @@ export const popup = {
|
||||
),
|
||||
};
|
||||
|
||||
/* ==========================================================================
|
||||
Sliders
|
||||
========================================================================== */
|
||||
|
||||
export const slider = {
|
||||
...baseSlider,
|
||||
value: cn(baseSlider.value, 'bottom-10'),
|
||||
};
|
||||
|
||||
/* ==========================================================================
|
||||
Error
|
||||
========================================================================== */
|
||||
@@ -98,5 +108,4 @@ export { icon, iconContainer, iconFlipped, iconHidden } from './components/icon'
|
||||
export { menu } from './components/menu';
|
||||
export { playbackRate } from './components/playback-rate';
|
||||
export { seek } from './components/seek';
|
||||
export { slider } from './components/slider';
|
||||
export { time } from './components/time';
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { cn } from '@videojs/utils/style';
|
||||
|
||||
export const preview = {
|
||||
root: 'group/preview pointer-events-none',
|
||||
thumbnailWrapper: 'relative rounded-lg bg-black/90',
|
||||
thumbnail: cn('block rounded-[inherit] transition-opacity duration-150 ease-out', 'data-loading:opacity-0'),
|
||||
time: 'mt-2 block text-center tabular-nums',
|
||||
spinner: cn(
|
||||
'absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-0',
|
||||
'transition-opacity duration-150 ease-out',
|
||||
'group-not-has-[[role=img][data-loading]]/preview:[--media-spinner-animation:none] group-has-[[role=img][data-loading]]/preview:opacity-100'
|
||||
),
|
||||
};
|
||||
@@ -40,7 +40,7 @@ export const slider = {
|
||||
base: cn(
|
||||
'z-10 absolute size-3 -translate-x-1/2 -translate-y-1/2',
|
||||
'bg-current rounded-full',
|
||||
'shadow-[0_0_0_1px_var(--media-current-shadow-color-subtle,oklch(0_0_0/0.1)),0_1px_3px_0_oklch(0_0_0/0.15),0_1px_2px_-1px_oklch(0_0_0/0.15)]',
|
||||
'shadow-[0_0_0_1px_var(--media-current-shadow-color,oklch(0_0_0/0.15)),0_1px_3px_0_oklch(0_0_0/0.15),0_1px_2px_-1px_oklch(0_0_0/0.15)]',
|
||||
'transition-[opacity,scale,outline-offset] duration-150 ease-out select-none',
|
||||
'outline-2 outline-transparent -outline-offset-2',
|
||||
'focus-visible:outline-current focus-visible:outline-offset-2',
|
||||
@@ -55,4 +55,21 @@ export const slider = {
|
||||
'group-focus-within/slider:opacity-100 group-focus-within/slider:scale-100'
|
||||
),
|
||||
},
|
||||
preview: cn(
|
||||
'group/preview',
|
||||
'before:block before:bg-current/35 before:opacity-0 before:scale-50',
|
||||
'before:transition-[opacity,scale] before:duration-200 before:ease-out',
|
||||
'data-pointing:not-data-dragging:before:opacity-100 data-pointing:not-data-dragging:before:scale-100',
|
||||
'data-[orientation=horizontal]:before:min-w-px data-[orientation=horizontal]:before:h-5',
|
||||
'data-[orientation=vertical]:before:w-5 data-[orientation=vertical]:before:min-h-px',
|
||||
'peer-has-[[role=img]:not([data-hidden])]/thumbnail:*:hidden'
|
||||
),
|
||||
value: cn(
|
||||
'absolute bottom-6 tabular-nums',
|
||||
'-translate-x-1/2 translate-y-2 scale-50 opacity-0 blur-lg',
|
||||
'text-shadow-2xs text-shadow-(color:--media-current-shadow-color)',
|
||||
'transition-[filter,opacity,scale,translate] duration-200 ease-out',
|
||||
'group-data-pointing/preview:translate-y-0 group-data-pointing/preview:scale-100',
|
||||
'group-data-pointing/preview:opacity-100 group-data-pointing/preview:blur-none'
|
||||
),
|
||||
};
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { cn } from '@videojs/utils/style';
|
||||
|
||||
export const thumbnail = {
|
||||
root: 'group/thumbnail peer/thumbnail pointer-events-none',
|
||||
imageWrapper: 'relative rounded-lg bg-black/90',
|
||||
image: cn('block rounded-[inherit] transition-opacity duration-150 ease-out', 'data-loading:opacity-0'),
|
||||
time: 'mt-2 block text-center tabular-nums',
|
||||
spinner: cn(
|
||||
'absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-0',
|
||||
'transition-opacity duration-150 ease-out',
|
||||
'group-not-has-[[role=img][data-loading]]/thumbnail:[--media-spinner-animation:none] group-has-[[role=img][data-loading]]/thumbnail:opacity-100'
|
||||
),
|
||||
};
|
||||
@@ -3,9 +3,9 @@ import { buttonGroup as baseButtonGroup } from './components/button-group';
|
||||
import { controls as baseControls } from './components/controls';
|
||||
import { error as baseError } from './components/error';
|
||||
import { popup as basePopup } from './components/popup';
|
||||
import { preview as basePreview } from './components/preview';
|
||||
import { root as baseRoot } from './components/root';
|
||||
import { slider as baseSlider } from './components/slider';
|
||||
import { thumbnail as baseThumbnail } from './components/thumbnail';
|
||||
import { time as baseTime } from './components/time';
|
||||
|
||||
/* ==========================================================================
|
||||
@@ -139,28 +139,29 @@ export const error = {
|
||||
};
|
||||
|
||||
/* ==========================================================================
|
||||
Preview
|
||||
Thumbnail
|
||||
========================================================================== */
|
||||
|
||||
export const preview = {
|
||||
...basePreview,
|
||||
export const thumbnail = {
|
||||
...baseThumbnail,
|
||||
root: cn(
|
||||
'[--media-preview-max-width:11rem] [--media-preview-padding:-0.5rem] [--media-preview-inset:calc(100cqi-100%)]',
|
||||
'absolute [left:clamp(calc(var(--media-preview-max-width)/2+var(--media-preview-padding)),var(--media-slider-pointer),calc(100%-var(--media-preview-max-width)/2-var(--media-preview-padding)+var(--media-preview-inset)))] bottom-full -translate-x-1/2',
|
||||
'@2xl/media-root:bottom-[calc(100%+0.25rem)] @2xl/media-root:[left:var(--media-slider-pointer)]',
|
||||
baseThumbnail.root,
|
||||
'[--media-slider-thumbnail-max-width:11rem] [--media-slider-thumbnail-padding:-0.5rem] [--media-slider-thumbnail-inset:calc(100cqi-100%)]',
|
||||
'absolute [left:clamp(calc(var(--media-slider-thumbnail-max-width)/2+var(--media-slider-thumbnail-padding)),var(--media-slider-pointer),calc(100%-var(--media-slider-thumbnail-max-width)/2-var(--media-slider-thumbnail-padding)+var(--media-slider-thumbnail-inset)))] bottom-full -translate-x-1/2',
|
||||
'@2xl/media-root:[left:var(--media-slider-pointer)]',
|
||||
'opacity-0 scale-80 blur-sm origin-bottom',
|
||||
'transition-[scale,opacity,filter] duration-150',
|
||||
'group-data-pointing/slider:opacity-100 group-data-pointing/slider:scale-100 group-data-pointing/slider:blur-none',
|
||||
'has-[[role=img][data-hidden]]:opacity-0 has-[[role=img][data-hidden]]:scale-80 has-[[role=img][data-hidden]]:blur-sm',
|
||||
'has-[[role=img][data-loading]]:max-h-24',
|
||||
basePreview.root
|
||||
'has-[[role=img]:not([data-hidden])]:group-data-pointing/slider:opacity-100',
|
||||
'has-[[role=img]:not([data-hidden])]:group-data-pointing/slider:scale-100',
|
||||
'has-[[role=img]:not([data-hidden])]:group-data-pointing/slider:blur-none',
|
||||
'has-[[role=img][data-loading]]:max-h-24'
|
||||
),
|
||||
thumbnailWrapper: cn(
|
||||
basePreview.thumbnailWrapper,
|
||||
imageWrapper: cn(
|
||||
baseThumbnail.imageWrapper,
|
||||
'after:absolute after:inset-0 after:rounded-[inherit]',
|
||||
'after:ring-1 after:ring-black/5 after:shadow-sm after:shadow-black/20'
|
||||
),
|
||||
thumbnail: cn(basePreview.thumbnail, 'max-w-(--media-preview-max-width)'),
|
||||
image: cn(baseThumbnail.image, 'max-w-(--media-slider-thumbnail-max-width)'),
|
||||
};
|
||||
|
||||
/* ==========================================================================
|
||||
|
||||
Reference in New Issue
Block a user