mirror of
https://github.com/zoriya/v10.git
synced 2026-08-05 05:37:21 +00:00
feat(ui): skin design improvements, add html frosted skin (WIP) (#133)
This commit is contained in:
+1
-1
@@ -3,7 +3,7 @@
|
||||
"ignorePaths": ["package.json", "tsconfig.json"],
|
||||
"dictionaryDefinitions": [],
|
||||
"dictionaries": ["css", "html", "node", "typescript", "npm"],
|
||||
"words": ["antfu", "noto", "nums", "rahim", "segoe"],
|
||||
"words": ["antfu", "noto", "nums", "rahim", "segoe", "videojs"],
|
||||
"ignoreWords": [],
|
||||
"import": []
|
||||
}
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>VJS HTML Demo</title>
|
||||
<link rel="preconnect" href="https://rsms.me/" />
|
||||
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
|
||||
<style>
|
||||
body {
|
||||
font-family:
|
||||
InterVariable, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||
'Noto Color Emoji';
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import { defineVjsPlayer } from '@videojs/html';
|
||||
|
||||
import '@videojs/html/skins/default';
|
||||
import '@videojs/html/skins/frosted';
|
||||
|
||||
defineVjsPlayer();
|
||||
|
||||
document.body.innerHTML = /* html */ `
|
||||
<media-provider>
|
||||
<div style="width: 100%; max-width: 800px; margin: 0 auto;">
|
||||
<media-skin-default>
|
||||
<div style="display: grid; place-items: center; min-height: 100vh;">
|
||||
<media-skin-frosted style="border-radius: 2rem; width: 100%; max-width: 800px; margin: 2rem auto;">
|
||||
<video slot="media" src="https://stream.mux.com/A3VXy02VoUinw01pwyomEO3bHnG4P32xzV7u1j1FSzjNg/high.mp4" muted></video>
|
||||
</media-skin-default>
|
||||
</media-skin-frosted>
|
||||
</div>
|
||||
</media-skin-default>
|
||||
</media-provider>
|
||||
`;
|
||||
|
||||
@@ -25,9 +25,13 @@
|
||||
"types": "./dist/icons.d.ts",
|
||||
"default": "./dist/icons.js"
|
||||
},
|
||||
"./skins/default": {
|
||||
"types": "./dist/skins/default.d.ts",
|
||||
"default": "./dist/skins/default.js"
|
||||
"./skins/frosted": {
|
||||
"types": "./dist/skins/frosted.d.ts",
|
||||
"default": "./dist/skins/frosted.js"
|
||||
},
|
||||
"./skins/minimal": {
|
||||
"types": "./dist/skins/minimal.d.ts",
|
||||
"default": "./dist/skins/minimal.js"
|
||||
}
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
|
||||
@@ -288,7 +288,7 @@ export class MediaPopoverPortal extends HTMLElement {
|
||||
if (!portalId) return;
|
||||
|
||||
/* @TODO We need to make sure portal logic is non-brittle longer term (CJP) */
|
||||
// NOTE: Hacky solution in part to ensure styling propogates from skin to container's baked in portal (TL;DR - Shadow DOM vs. Light DOM CSS) (CJP)
|
||||
// NOTE: Hacky solution in part to ensure styling propagates from skin to container's baked in portal (TL;DR - Shadow DOM vs. Light DOM CSS) (CJP)
|
||||
const portalContainer
|
||||
= ((this.getRootNode() as ShadowRoot | Document).getElementById(portalId)
|
||||
?? (this.getRootNode() as ShadowRoot | Document)
|
||||
|
||||
@@ -1,390 +0,0 @@
|
||||
import { MediaSkin } from '@/media/media-skin';
|
||||
import '@/media/media-container';
|
||||
import '@/media/media-provider';
|
||||
import '@/components/media-play-button';
|
||||
import '@/components/media-mute-button';
|
||||
import '@/components/media-volume-slider';
|
||||
import '@/components/media-time-slider';
|
||||
import '@/components/media-fullscreen-button';
|
||||
import '@/components/media-duration-display';
|
||||
import '@/components/media-current-time-display';
|
||||
import '@/components/media-preview-time-display';
|
||||
import '@/components/media-popover';
|
||||
import '@/components/media-tooltip';
|
||||
import '@/icons';
|
||||
|
||||
export function getTemplateHTML() {
|
||||
return /* html */`
|
||||
${MediaSkin.getTemplateHTML()}
|
||||
<style>
|
||||
/** @TODO: Improve/Polish CSS Here */
|
||||
/* Media Container UI/Styles */
|
||||
media-container {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
/* NOTE: Setting color here for generic inheritance, including SVG fill: currentColor defaults (CJP) */
|
||||
color: rgb(238 238 238);
|
||||
}
|
||||
|
||||
media-container > ::slotted([slot=media]) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Media Container UI Overlay Styling */
|
||||
media-container > .overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: start;
|
||||
pointer-events: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* Time Display Styling */
|
||||
media-current-time-display,
|
||||
media-duration-display {
|
||||
padding: 4px 8px;
|
||||
color: rgb(238 238 238);
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
border-radius: 2px;
|
||||
min-width: 3em;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Generic Media Button Styling */
|
||||
.button {
|
||||
border: none;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
color: rgb(238 238 238);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
.button .icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Media Play Button UI/Styles */
|
||||
media-play-button:not([data-paused]) .pause-icon,
|
||||
media-play-button[data-paused] .play-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Media Fullscreen Button UI/Styles */
|
||||
media-fullscreen-button:not([data-fullscreen]) .fullscreen-enter-icon,
|
||||
media-fullscreen-button[data-fullscreen] .fullscreen-exit-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* One way to define the "default visible" icon (CJP) */
|
||||
media-mute-button:not([data-volume-level]) .volume-low-icon,
|
||||
media-mute-button[data-volume-level=high] .volume-high-icon,
|
||||
media-mute-button[data-volume-level=low] .volume-low-icon,
|
||||
media-mute-button[data-volume-level=medium] .volume-low-icon,
|
||||
media-mute-button[data-volume-level=off] .volume-off-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Media Control Bar UI/Styles */
|
||||
.control-bar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgb(20 20 30 / .7);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* TimeSlider Component Styles */
|
||||
media-time-slider-root {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
min-width: 100px;
|
||||
width: 100%;
|
||||
margin: 0 .5rem;
|
||||
}
|
||||
|
||||
/* Horizontal orientation styles */
|
||||
media-time-slider-root[data-orientation="horizontal"] {
|
||||
min-width: 100px;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
/* Vertical orientation styles */
|
||||
media-time-slider-root[data-orientation="vertical"] {
|
||||
min-width: 20px;
|
||||
width: 20px;
|
||||
height: 100px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
media-time-slider-track {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: .375rem;
|
||||
background-color: #e0e0e0;
|
||||
border-radius: .25rem;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Horizontal track styles */
|
||||
media-time-slider-track[data-orientation="horizontal"] {
|
||||
width: 100%;
|
||||
height: .375rem;
|
||||
}
|
||||
|
||||
/* Vertical track styles */
|
||||
media-time-slider-track[data-orientation="vertical"] {
|
||||
width: .375rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
media-time-slider-thumb {
|
||||
width: .75rem;
|
||||
height: .75rem;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
media-time-slider-pointer {
|
||||
background-color: rgba(255, 255, 255, .5);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
media-time-slider-progress {
|
||||
background-color: #007bff;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
media-popover-popup {
|
||||
background: rgb(20 20 30 / .7);
|
||||
padding: 14px 0;
|
||||
--transition: .15s ease-in-out;
|
||||
transition: transform var(--transition), scale var(--transition), opacity var(--transition);
|
||||
}
|
||||
|
||||
media-popover-popup[data-starting-style] {
|
||||
transition-duration: 0s;
|
||||
transform: scale(0.9) translateY(8px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
media-popover-popup[data-ending-style] {
|
||||
transform: scale(0.9) translateY(8px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* VolumeSlider Component Styles */
|
||||
media-volume-slider-root {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
min-width: 80px;
|
||||
width: 80px;
|
||||
margin: 0 .5rem;
|
||||
}
|
||||
|
||||
/* Horizontal orientation styles */
|
||||
media-volume-slider-root[data-orientation="horizontal"] {
|
||||
min-width: 80px;
|
||||
width: 80px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
/* Vertical orientation styles */
|
||||
media-volume-slider-root[data-orientation="vertical"] {
|
||||
min-width: 20px;
|
||||
width: 20px;
|
||||
height: 80px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
media-volume-slider-track {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: .375rem;
|
||||
background-color: #e0e0e0;
|
||||
border-radius: .25rem;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Horizontal track styles */
|
||||
media-volume-slider-track[data-orientation="horizontal"] {
|
||||
width: 100%;
|
||||
height: .375rem;
|
||||
}
|
||||
|
||||
/* Vertical track styles */
|
||||
media-volume-slider-track[data-orientation="vertical"] {
|
||||
width: .375rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
media-volume-slider-thumb {
|
||||
width: .75rem;
|
||||
height: .75rem;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
media-volume-slider-progress {
|
||||
background-color: #007bff;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
/* Tooltip Component Styles */
|
||||
media-tooltip-popup {
|
||||
background: rgb(20 20 30 / .9);
|
||||
color: rgb(238 238 238);
|
||||
padding: 6px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
--transition: .15s ease-in-out;
|
||||
transition: transform var(--transition), scale var(--transition), opacity var(--transition);
|
||||
}
|
||||
|
||||
media-tooltip-popup[data-starting-style] {
|
||||
transition-duration: 0s;
|
||||
transform: scale(0.9);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
media-tooltip-popup[data-ending-style] {
|
||||
transform: scale(0.9);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
display: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
media-tooltip-popup[data-paused] .play-tooltip,
|
||||
media-tooltip-popup:not([data-paused]) .pause-tooltip {
|
||||
display: block;
|
||||
}
|
||||
|
||||
media-tooltip-popup[data-fullscreen] .fullscreen-exit-tooltip,
|
||||
media-tooltip-popup:not([data-fullscreen]) .fullscreen-enter-tooltip {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<media-container>
|
||||
<slot name="media" slot="media"></slot>
|
||||
<div class="overlay"></div>
|
||||
|
||||
<div class="control-bar">
|
||||
<!-- NOTE: We can decide if we further want to provide a further, "themed" media-play-button that comes with baked in default styles and icons. (CJP) -->
|
||||
<media-tooltip-root delay="600" close-delay="0">
|
||||
<media-tooltip-trigger>
|
||||
<media-play-button class="button">
|
||||
<media-play-icon class="icon play-icon"></media-play-icon>
|
||||
<media-pause-icon class="icon pause-icon"></media-pause-icon>
|
||||
</media-play-button>
|
||||
</media-tooltip-trigger>
|
||||
<media-tooltip-portal>
|
||||
<media-tooltip-positioner side="top" side-offset="8" collision-padding="8">
|
||||
<media-tooltip-popup>
|
||||
<span class="tooltip play-tooltip">Play</span>
|
||||
<span class="tooltip pause-tooltip">Pause</span>
|
||||
</media-tooltip-popup>
|
||||
</media-tooltip-positioner>
|
||||
</media-tooltip-portal>
|
||||
</media-tooltip-root>
|
||||
<!-- Use the show-remaining attribute to show count down/remaining time -->
|
||||
<media-current-time-display show-remaining></media-current-time-display>
|
||||
|
||||
<media-tooltip-root track-cursor-axis="x">
|
||||
<media-tooltip-trigger>
|
||||
<media-time-slider-root>
|
||||
<media-time-slider-track>
|
||||
<media-time-slider-progress></media-time-slider-progress>
|
||||
<media-time-slider-pointer></media-time-slider-pointer>
|
||||
</media-time-slider-track>
|
||||
<media-time-slider-thumb></media-time-slider-thumb>
|
||||
</media-time-slider-root>
|
||||
</media-tooltip-trigger>
|
||||
<media-tooltip-portal>
|
||||
<media-tooltip-positioner side="top" side-offset="18" collision-padding="12">
|
||||
<media-tooltip-popup>
|
||||
<preview-time-display></preview-time-display>
|
||||
</media-tooltip-popup>
|
||||
</media-tooltip-positioner>
|
||||
</media-tooltip-portal>
|
||||
</media-tooltip-root>
|
||||
|
||||
<media-duration-display></media-duration-display>
|
||||
<media-popover-root open-on-hover delay="200" close-delay="100">
|
||||
<media-popover-trigger>
|
||||
<media-mute-button class="button">
|
||||
<media-volume-high-icon class="icon volume-high-icon"></media-volume-high-icon>
|
||||
<media-volume-low-icon class="icon volume-low-icon"></media-volume-low-icon>
|
||||
<media-volume-off-icon class="icon volume-off-icon"></media-volume-off-icon>
|
||||
</media-mute-button>
|
||||
</media-popover-trigger>
|
||||
<media-popover-portal>
|
||||
<media-popover-positioner side="top">
|
||||
<media-popover-popup>
|
||||
<media-volume-slider-root orientation="vertical">
|
||||
<media-volume-slider-track>
|
||||
<media-volume-slider-progress></media-volume-slider-progress>
|
||||
</media-volume-slider-track>
|
||||
<media-volume-slider-thumb></media-volume-slider-thumb>
|
||||
</media-volume-slider-root>
|
||||
</media-popover-popup>
|
||||
</media-popover-positioner>
|
||||
</media-popover-portal>
|
||||
</media-popover-root>
|
||||
<media-tooltip-root delay="600" close-delay="0">
|
||||
<media-tooltip-trigger>
|
||||
<media-fullscreen-button class="button">
|
||||
<media-fullscreen-enter-icon class="icon fullscreen-enter-icon"></media-fullscreen-enter-icon>
|
||||
<media-fullscreen-exit-icon class="icon fullscreen-exit-icon"></media-fullscreen-exit-icon>
|
||||
</media-fullscreen-button>
|
||||
</media-tooltip-trigger>
|
||||
<media-tooltip-portal>
|
||||
<media-tooltip-positioner side="top" side-offset="8" collision-padding="8">
|
||||
<media-tooltip-popup>
|
||||
<span class="tooltip fullscreen-enter-tooltip">Enter Fullscreen</span>
|
||||
<span class="tooltip fullscreen-exit-tooltip">Exit Fullscreen</span>
|
||||
</media-tooltip-popup>
|
||||
</media-tooltip-positioner>
|
||||
</media-tooltip-portal>
|
||||
</media-tooltip-root>
|
||||
</div>
|
||||
</media-container>
|
||||
`;
|
||||
}
|
||||
|
||||
export class MediaSkinDefault extends MediaSkin {
|
||||
static getTemplateHTML: () => string = getTemplateHTML;
|
||||
}
|
||||
|
||||
customElements.define('media-skin-default', MediaSkinDefault);
|
||||
@@ -0,0 +1,119 @@
|
||||
import { MediaSkin } from '@/media/media-skin';
|
||||
import styles from './styles.css';
|
||||
import '@/media/media-container';
|
||||
import '@/media/media-provider';
|
||||
import '@/components/media-play-button';
|
||||
import '@/components/media-mute-button';
|
||||
import '@/components/media-volume-slider';
|
||||
import '@/components/media-time-slider';
|
||||
import '@/components/media-fullscreen-button';
|
||||
import '@/components/media-duration-display';
|
||||
import '@/components/media-current-time-display';
|
||||
import '@/components/media-preview-time-display';
|
||||
import '@/components/media-popover';
|
||||
import '@/components/media-tooltip';
|
||||
|
||||
import '@/icons';
|
||||
|
||||
export function getTemplateHTML() {
|
||||
return /* html */`
|
||||
${MediaSkin.getTemplateHTML()}
|
||||
<style>${styles}</style>
|
||||
|
||||
<media-container>
|
||||
<slot name="media" slot="media"></slot>
|
||||
<div class="overlay"></div>
|
||||
|
||||
<div class="control-bar surface">
|
||||
<!-- NOTE: We can decide if we further want to provide a further, "themed" media-play-button that comes with baked in default styles and icons. (CJP) -->
|
||||
<media-tooltip-root delay="600" close-delay="0">
|
||||
<media-tooltip-trigger>
|
||||
<media-play-button class="button">
|
||||
<media-play-icon class="icon play-icon"></media-play-icon>
|
||||
<media-pause-icon class="icon pause-icon"></media-pause-icon>
|
||||
</media-play-button>
|
||||
</media-tooltip-trigger>
|
||||
<media-tooltip-portal>
|
||||
<media-tooltip-positioner side="top" side-offset="12" collision-padding="12">
|
||||
<media-tooltip-popup class="surface popup-animation">
|
||||
<span class="tooltip play-tooltip">Play</span>
|
||||
<span class="tooltip pause-tooltip">Pause</span>
|
||||
</media-tooltip-popup>
|
||||
</media-tooltip-positioner>
|
||||
</media-tooltip-portal>
|
||||
</media-tooltip-root>
|
||||
|
||||
<div class="time-controls">
|
||||
<!-- Use the show-remaining attribute to show count down/remaining time -->
|
||||
<media-current-time-display show-remaining></media-current-time-display>
|
||||
|
||||
<media-tooltip-root track-cursor-axis="x">
|
||||
<media-tooltip-trigger>
|
||||
<media-time-slider-root class="slider-root">
|
||||
<media-time-slider-track class="slider-track">
|
||||
<media-time-slider-progress class="slider-progress"></media-time-slider-progress>
|
||||
<media-time-slider-pointer class="slider-pointer"></media-time-slider-pointer>
|
||||
</media-time-slider-track>
|
||||
<media-time-slider-thumb class="slider-thumb"></media-time-slider-thumb>
|
||||
</media-time-slider-root>
|
||||
</media-tooltip-trigger>
|
||||
<media-tooltip-portal>
|
||||
<media-tooltip-positioner side="top" side-offset="18" collision-padding="12">
|
||||
<media-tooltip-popup class="surface popup-animation">
|
||||
<preview-time-display></preview-time-display>
|
||||
</media-tooltip-popup>
|
||||
</media-tooltip-positioner>
|
||||
</media-tooltip-portal>
|
||||
</media-tooltip-root>
|
||||
|
||||
<media-duration-display></media-duration-display>
|
||||
</div>
|
||||
|
||||
<media-popover-root open-on-hover delay="200" close-delay="100">
|
||||
<media-popover-trigger>
|
||||
<media-mute-button class="button">
|
||||
<media-volume-high-icon class="icon volume-high-icon"></media-volume-high-icon>
|
||||
<media-volume-low-icon class="icon volume-low-icon"></media-volume-low-icon>
|
||||
<media-volume-off-icon class="icon volume-off-icon"></media-volume-off-icon>
|
||||
</media-mute-button>
|
||||
</media-popover-trigger>
|
||||
<media-popover-portal>
|
||||
<media-popover-positioner side="top" side-offset="12" collision-padding="12">
|
||||
<media-popover-popup class="surface popup-animation">
|
||||
<media-volume-slider-root class="slider-root" orientation="vertical">
|
||||
<media-volume-slider-track class="slider-track">
|
||||
<media-volume-slider-progress class="slider-progress"></media-volume-slider-progress>
|
||||
</media-volume-slider-track>
|
||||
<media-volume-slider-thumb class="slider-thumb"></media-volume-slider-thumb>
|
||||
</media-volume-slider-root>
|
||||
</media-popover-popup>
|
||||
</media-popover-positioner>
|
||||
</media-popover-portal>
|
||||
</media-popover-root>
|
||||
|
||||
<media-tooltip-root delay="600" close-delay="0">
|
||||
<media-tooltip-trigger>
|
||||
<media-fullscreen-button class="button">
|
||||
<media-fullscreen-enter-icon class="icon fullscreen-enter-icon"></media-fullscreen-enter-icon>
|
||||
<media-fullscreen-exit-icon class="icon fullscreen-exit-icon"></media-fullscreen-exit-icon>
|
||||
</media-fullscreen-button>
|
||||
</media-tooltip-trigger>
|
||||
<media-tooltip-portal>
|
||||
<media-tooltip-positioner side="top" side-offset="12" collision-padding="12">
|
||||
<media-tooltip-popup class="surface popup-animation">
|
||||
<span class="tooltip fullscreen-enter-tooltip">Enter Fullscreen</span>
|
||||
<span class="tooltip fullscreen-exit-tooltip">Exit Fullscreen</span>
|
||||
</media-tooltip-popup>
|
||||
</media-tooltip-positioner>
|
||||
</media-tooltip-portal>
|
||||
</media-tooltip-root>
|
||||
</div>
|
||||
</media-container>
|
||||
`;
|
||||
}
|
||||
|
||||
export class MediaSkinFrosted extends MediaSkin {
|
||||
static getTemplateHTML: () => string = getTemplateHTML;
|
||||
}
|
||||
|
||||
customElements.define('media-skin-frosted', MediaSkinFrosted);
|
||||
@@ -0,0 +1,351 @@
|
||||
media-container * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
media-container {
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
container: root / inline-size;
|
||||
overflow: clip;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.5;
|
||||
border-radius: inherit;
|
||||
}
|
||||
media-container::before,
|
||||
media-container::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border-radius: inherit;
|
||||
z-index: 10;
|
||||
}
|
||||
media-container::before {
|
||||
inset: 1px;
|
||||
box-shadow: inset 0 0 0 1px oklab(1 0 0 / 0.15);
|
||||
}
|
||||
media-container::after {
|
||||
inset: 0;
|
||||
box-shadow: inset 0 0 0 1px oklab(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
/* Fullscreen */
|
||||
media-container:fullscreen {
|
||||
border-radius: 0;
|
||||
}
|
||||
media-container:fullscreen video {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
media-container > ::slotted([slot='media']) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Media Container UI Overlay Styling */
|
||||
media-container > .overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: start;
|
||||
pointer-events: none;
|
||||
background-image: linear-gradient(to top, oklab(0 0 0 / 0.5), oklab(0 0 0 / 0.3), rgba(0, 0, 0, 0));
|
||||
backdrop-filter: saturate(1.5) brightness(0.9);
|
||||
transition: opacity 0.15s ease-out;
|
||||
transition-delay: 500ms;
|
||||
opacity: 0;
|
||||
}
|
||||
media-container:hover > .overlay,
|
||||
media-container:has([data-paused]) > .overlay,
|
||||
media-container:has([aria-expanded='true']) > .overlay {
|
||||
opacity: 1;
|
||||
transition-delay: 0ms;
|
||||
}
|
||||
|
||||
/* Common Surface Styles - e.g. tooltips, popovers, controls */
|
||||
.surface {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(64px) brightness(0.9) saturate(1.5);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px oklab(1 0 0 / 0.15),
|
||||
0 0 0 1px oklab(0 0 0 / 0.15),
|
||||
oklab(0 0 0 / 0.15) 0px 1px 3px 0px,
|
||||
oklab(0 0 0 / 0.15) 0px 1px 2px -1px;
|
||||
}
|
||||
@media (prefers-reduced-transparency: reduce) {
|
||||
.surface {
|
||||
background-color: oklab(0 0 0 / 0.7);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px oklab(0 0 0),
|
||||
0 0 0 1px oklab(1 0 0 / 0.2);
|
||||
}
|
||||
}
|
||||
@media (prefers-contrast: more) {
|
||||
.surface {
|
||||
background-color: oklab(0 0 0 / 0.9);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px oklab(0 0 0),
|
||||
0 0 0 1px oklab(1 0 0 / 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Media Control Bar UI/Styles */
|
||||
.control-bar {
|
||||
position: absolute;
|
||||
bottom: 0.75rem;
|
||||
inset-inline: 0.75rem;
|
||||
padding: 0.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.125rem;
|
||||
border-radius: calc(infinity * 1px);
|
||||
will-change: scale, transform, filter, opacity;
|
||||
scale: 0.9;
|
||||
opacity: 0;
|
||||
filter: blur(8px);
|
||||
transition-property: scale, transform, filter, opacity;
|
||||
transition-delay: 500ms;
|
||||
transition-duration: 300ms;
|
||||
transition-timing-function: ease-out;
|
||||
transform-origin: bottom;
|
||||
color: oklab(1 0 0);
|
||||
}
|
||||
media-container:hover > .control-bar,
|
||||
media-container:has([data-paused]) > .control-bar,
|
||||
media-container:has([aria-expanded='true']) > .control-bar {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
filter: blur(0px);
|
||||
transition-delay: 0ms;
|
||||
transition-duration: 100ms;
|
||||
}
|
||||
|
||||
/* Time Display Styling */
|
||||
.time-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
gap: 0.75rem;
|
||||
padding-inline: 0.375rem;
|
||||
}
|
||||
media-current-time-display,
|
||||
media-duration-display {
|
||||
text-shadow: 0 1px 0 oklab(0 0 0 / 0.25);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Generic Media Button Styling */
|
||||
.button {
|
||||
display: grid;
|
||||
flex-shrink: 0;
|
||||
padding: 0.5rem;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: calc(infinity * 1px);
|
||||
color: oklab(1 0 0 / 0.9);
|
||||
user-select: none;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: -2px;
|
||||
transition-property: background-color, color, outline-offset;
|
||||
transition-duration: 150ms;
|
||||
transition-timing-function: ease-out;
|
||||
}
|
||||
.button:hover,
|
||||
.button:focus-visible,
|
||||
.button[aria-expanded='true'] {
|
||||
background-color: oklab(1 0 0 / 0.1);
|
||||
color: oklab(1 0 0);
|
||||
text-decoration: none;
|
||||
}
|
||||
.button:focus-visible {
|
||||
outline-color: oklch(62.3% 0.214 259.815);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.button[disabled] {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
.button .icon {
|
||||
grid-area: 1 / 1;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
filter: drop-shadow(0 1px 0 oklab(0 0 0 / 0.25));
|
||||
}
|
||||
|
||||
/* Media Play Button UI/Styles */
|
||||
media-play-button .icon {
|
||||
opacity: 0;
|
||||
transition: opacity 150ms linear;
|
||||
}
|
||||
|
||||
media-play-button:not([data-paused]) .pause-icon,
|
||||
media-play-button[data-paused] .play-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Media Fullscreen Button UI/Styles */
|
||||
media-fullscreen-button .icon {
|
||||
display: none;
|
||||
}
|
||||
media-fullscreen-button:not([data-fullscreen]) .fullscreen-enter-icon,
|
||||
media-fullscreen-button[data-fullscreen] .fullscreen-exit-icon {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* One way to define the "default visible" icon (CJP) */
|
||||
media-mute-button .icon {
|
||||
display: none;
|
||||
}
|
||||
media-mute-button:not([data-volume-level]) .volume-low-icon,
|
||||
media-mute-button[data-volume-level='high'] .volume-high-icon,
|
||||
media-mute-button[data-volume-level='low'] .volume-low-icon,
|
||||
media-mute-button[data-volume-level='medium'] .volume-low-icon,
|
||||
media-mute-button[data-volume-level='off'] .volume-off-icon {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* TimeSlider Component Styles */
|
||||
.slider-root {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
border-radius: calc(infinity * 1px);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Horizontal orientation styles */
|
||||
.slider-root[data-orientation='horizontal'] {
|
||||
min-width: 80px;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
/* Vertical orientation styles */
|
||||
.slider-root[data-orientation='vertical'] {
|
||||
height: 80px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.slider-track {
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
background-color: oklab(1 0 0 / 0.2);
|
||||
border-radius: inherit;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: -2px;
|
||||
transition: outline-offset 150ms ease-out;
|
||||
box-shadow: 0 0 0 1px oklab(0 0 0 / 0.05);
|
||||
}
|
||||
|
||||
/* Horizontal track styles */
|
||||
.slider-track[data-orientation='horizontal'] {
|
||||
width: 100%;
|
||||
height: 0.25rem;
|
||||
}
|
||||
|
||||
/* Vertical track styles */
|
||||
.slider-track[data-orientation='vertical'] {
|
||||
width: 0.25rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.slider-root:focus-visible .slider-track {
|
||||
outline-color: oklch(62.3% 0.214 259.815);
|
||||
outline-offset: 6px;
|
||||
}
|
||||
|
||||
.slider-thumb {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
background-color: oklab(1 0 0);
|
||||
border-radius: calc(infinity * 1px);
|
||||
user-select: none;
|
||||
z-index: 10;
|
||||
box-shadow:
|
||||
0 0 0 1px oklab(0 0 0 / 0.1),
|
||||
0 1px 3px 0 oklab(0 0 0 / 0.15),
|
||||
0 1px 2px -1px oklab(0 0 0 / 0.15);
|
||||
opacity: 0;
|
||||
transition-property: opacity, height, width;
|
||||
transition-duration: 150ms;
|
||||
transition-timing-function: ease-in-out;
|
||||
}
|
||||
.slider-thumb:active {
|
||||
width: 0.75rem;
|
||||
height: 0.75rem;
|
||||
}
|
||||
.slider-root:hover .slider-thumb,
|
||||
.slider-root:focus-within .slider-thumb {
|
||||
opacity: 1;
|
||||
}
|
||||
.slider-track[data-orientation='horizontal'] .slider-thumb {
|
||||
cursor: ew-resize;
|
||||
}
|
||||
.slider-track[data-orientation='vertical'] .slider-thumb {
|
||||
cursor: ns-resize;
|
||||
}
|
||||
|
||||
.slider-pointer {
|
||||
background-color: oklab(1 0 0 / 0.2);
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.slider-progress {
|
||||
background-color: oklab(1 0 0);
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.popup-animation {
|
||||
transition-property: transform, scale, opacity, filter;
|
||||
transition-duration: 200ms;
|
||||
transform: scale(1);
|
||||
transform-origin: bottom;
|
||||
opacity: 1;
|
||||
filter: blur(0px);
|
||||
}
|
||||
.popup-animation[data-starting-style],
|
||||
.popup-animation[data-ending-style] {
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
filter: blur(8px);
|
||||
}
|
||||
.popup-animation[data-instant] {
|
||||
transition-duration: 0ms;
|
||||
}
|
||||
|
||||
media-popover-popup {
|
||||
padding: 0.75rem 0.25rem;
|
||||
border-radius: calc(infinity * 1px);
|
||||
}
|
||||
|
||||
/* Tooltip Component Styles */
|
||||
media-tooltip-popup {
|
||||
color: oklab(1 0 0);
|
||||
padding: 0.25rem 0.625rem;
|
||||
border-radius: calc(infinity * 1px);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
display: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
media-tooltip-popup[data-paused] .play-tooltip,
|
||||
media-tooltip-popup:not([data-paused]) .pause-tooltip {
|
||||
display: block;
|
||||
}
|
||||
|
||||
media-tooltip-popup[data-fullscreen] .fullscreen-exit-tooltip,
|
||||
media-tooltip-popup:not([data-fullscreen]) .fullscreen-enter-tooltip {
|
||||
display: block;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { MediaSkin } from '@/media/media-skin';
|
||||
import '@/media/media-container';
|
||||
import '@/media/media-provider';
|
||||
import '@/components/media-play-button';
|
||||
import '@/components/media-mute-button';
|
||||
import '@/components/media-volume-slider';
|
||||
import '@/components/media-time-slider';
|
||||
import '@/components/media-fullscreen-button';
|
||||
import '@/components/media-duration-display';
|
||||
import '@/components/media-current-time-display';
|
||||
import '@/components/media-preview-time-display';
|
||||
import '@/components/media-popover';
|
||||
import '@/components/media-tooltip';
|
||||
import '@/icons';
|
||||
|
||||
export function getTemplateHTML() {
|
||||
return /* html */`
|
||||
${MediaSkin.getTemplateHTML()}
|
||||
`;
|
||||
}
|
||||
|
||||
export class MediaSkinMinimal extends MediaSkin {
|
||||
static getTemplateHTML: () => string = getTemplateHTML;
|
||||
}
|
||||
|
||||
customElements.define('media-skin-minimal', MediaSkinMinimal);
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
declare module '*.css' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
@@ -5,7 +5,8 @@ export default defineConfig({
|
||||
index: './src/index.ts',
|
||||
store: './src/store/index.ts',
|
||||
icons: './src/icons/index.ts',
|
||||
'skins/default': './src/skins/default/index.ts',
|
||||
'skins/frosted': './src/skins/frosted/index.ts',
|
||||
'skins/minimal': './src/skins/minimal/index.ts',
|
||||
},
|
||||
platform: 'browser',
|
||||
format: 'es',
|
||||
@@ -19,5 +20,6 @@ export default defineConfig({
|
||||
},
|
||||
loader: {
|
||||
'.svg': 'text',
|
||||
'.css': 'text',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -46,18 +46,18 @@ const styles: FrostedSkinStyles = {
|
||||
Controls: cn(
|
||||
'vjs:@container/controls vjs:absolute vjs:inset-x-3 vjs:bottom-3 vjs:rounded-full vjs:flex vjs:items-center vjs:p-1 vjs:gap-0.5 vjs:text-white',
|
||||
// Animation
|
||||
'vjs:transition vjs:will-change-transform vjs:origin-bottom vjs:ease-out',
|
||||
'vjs:transition vjs:will-change-[transform,scale,filter,opacity] vjs:origin-bottom vjs:ease-out',
|
||||
// FIXME: Temporary className hook for above logic in the overlay. Can be removed once have a proper way to handle controls visibility.
|
||||
'controls',
|
||||
// FIXME: Temporary hide/show logic
|
||||
'vjs:scale-90 vjs:opacity-0 vjs:delay-500 vjs:duration-300',
|
||||
'vjs:has-[[data-paused]]:scale-100 vjs:has-[[data-paused]]:opacity-100 vjs:has-[[data-paused]]:delay-0',
|
||||
'vjs:has-[[aria-expanded="true"]]:scale-100 vjs:has-[[aria-expanded="true"]]:opacity-100 vjs:has-[[aria-expanded="true"]]:delay-0',
|
||||
'vjs:group-hover/root:scale-100 vjs:group-hover/root:opacity-100 vjs:group-hover/root:delay-0',
|
||||
'vjs:scale-90 vjs:opacity-0 vjs:blur-sm vjs:delay-500 vjs:duration-300',
|
||||
'vjs:has-[[data-paused]]:scale-100 vjs:has-[[data-paused]]:opacity-100 vjs:has-[[data-paused]]:blur-none vjs:has-[[data-paused]]:delay-0 vjs:has-[[data-paused]]:duration-100',
|
||||
'vjs:has-[[aria-expanded="true"]]:scale-100 vjs:has-[[aria-expanded="true"]]:opacity-100 vjs:has-[[aria-expanded="true"]]:blur-none vjs:has-[[aria-expanded="true"]]:delay-0 vjs:has-[[aria-expanded="true"]]:duration-100',
|
||||
'vjs:group-hover/root:scale-100 vjs:group-hover/root:opacity-100 vjs:group-hover/root:blur-none vjs:group-hover/root:delay-0 vjs:group-hover/root:duration-100',
|
||||
),
|
||||
Icon: cn('icon'),
|
||||
Button: cn(
|
||||
'vjs:group/button vjs:cursor-pointer vjs:relative vjs:shrink-0 vjs:transition vjs:select-none vjs:p-2 vjs:rounded-full',
|
||||
'vjs:group/button vjs:cursor-pointer vjs:relative vjs:shrink-0 vjs:transition-[color,background,outline-offset] vjs:select-none vjs:p-2 vjs:rounded-full',
|
||||
// Background/foreground
|
||||
'vjs:bg-transparent vjs:text-white/90',
|
||||
// Hover and focus states
|
||||
@@ -65,21 +65,19 @@ const styles: FrostedSkinStyles = {
|
||||
// Focus state
|
||||
'vjs:-outline-offset-2 vjs:focus-visible:outline-2 vjs:focus-visible:outline-offset-2 vjs:focus-visible:outline-blue-500',
|
||||
// Disabled state
|
||||
'vjs:aria-disabled:grayscale vjs:aria-disabled:opacity-50 vjs:aria-disabled:cursor-not-allowed',
|
||||
'vjs:disabled:grayscale vjs:disabled:opacity-50 vjs:disabled:cursor-not-allowed',
|
||||
// Loading state
|
||||
'vjs:aria-busy:pointer-events-none vjs:aria-busy:cursor-not-allowed',
|
||||
// Expanded state
|
||||
'vjs:aria-expanded:bg-white/10 vjs:aria-expanded:text-white',
|
||||
// Pressed state
|
||||
'vjs:active:scale-95',
|
||||
),
|
||||
IconButton: cn(
|
||||
'vjs:grid vjs:[&_.icon]:[grid-area:1/1]',
|
||||
'vjs:[&_.icon]:shrink-0 vjs:[&_.icon]:transition-[opacity,filter] vjs:[&_.icon]:duration-500 vjs:[&_.icon]:linear vjs:[&_.icon]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] vjs:[&_.icon]:shadow-black/25',
|
||||
'vjs:[&_.icon]:shrink-0 vjs:[&_.icon]:transition-opacity vjs:[&_.icon]:duration-150 vjs:[&_.icon]:ease-linear vjs:[&_.icon]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] vjs:[&_.icon]:shadow-black/25',
|
||||
),
|
||||
PlayButton: cn(
|
||||
'vjs:[&_.pause-icon]:opacity-100 vjs:[&[data-paused]_.pause-icon]:opacity-0 vjs:[&[data-paused]_.pause-icon]:blur-sm',
|
||||
'vjs:[&_.play-icon]:opacity-0 vjs:[&_.play-icon]:blur-sm vjs:[&[data-paused]_.play-icon]:opacity-100 vjs:[&[data-paused]_.play-icon]:blur-none',
|
||||
'vjs:[&_.pause-icon]:opacity-100 vjs:[&[data-paused]_.pause-icon]:opacity-0',
|
||||
'vjs:[&_.play-icon]:opacity-0 vjs:[&[data-paused]_.play-icon]:opacity-100',
|
||||
),
|
||||
PlayIcon: cn('play-icon'),
|
||||
PauseIcon: cn('pause-icon'),
|
||||
@@ -132,10 +130,10 @@ const styles: FrostedSkinStyles = {
|
||||
'vjs:[&[data-orientation="vertical"]]:w-5 vjs:[&[data-orientation="vertical"]]:h-20',
|
||||
),
|
||||
SliderTrack: cn(
|
||||
'vjs:-outline-offset-2 vjs:group-focus-visible/slider-root:outline-2 vjs:group-focus-visible/slider-root:outline-offset-2 vjs:group-focus-visible/slider-root:outline-blue-500',
|
||||
'vjs:w-full vjs:relative vjs:select-none vjs:rounded-full vjs:bg-white/20 vjs:ring-1 vjs:ring-black/5',
|
||||
'vjs:[&[data-orientation="horizontal"]]:h-1',
|
||||
'vjs:relative vjs:select-none vjs:transition-[outline-offset] vjs:rounded-[inherit] vjs:bg-white/20 vjs:ring-1 vjs:ring-black/5',
|
||||
'vjs:[&[data-orientation="horizontal"]]:w-full vjs:[&[data-orientation="horizontal"]]:h-1',
|
||||
'vjs:[&[data-orientation="vertical"]]:w-1',
|
||||
'vjs:-outline-offset-2 vjs:group-focus-visible/slider-root:outline-2 vjs:group-focus-visible/slider-root:outline-offset-6 vjs:group-focus-visible/slider-root:outline-blue-500',
|
||||
),
|
||||
SliderProgress: cn('vjs:bg-white vjs:rounded-[inherit]'),
|
||||
// TODO: Work out what we want to do here.
|
||||
@@ -143,7 +141,6 @@ const styles: FrostedSkinStyles = {
|
||||
SliderThumb: cn(
|
||||
'vjs:bg-white vjs:z-10 vjs:select-none vjs:ring vjs:ring-black/10 vjs:rounded-full vjs:shadow-sm vjs:shadow-black/15',
|
||||
'vjs:opacity-0 vjs:transition-[opacity,height,width] vjs:ease-in-out',
|
||||
'vjs:-outline-offset-2 vjs:focus-visible:outline-2 vjs:focus-visible:outline-offset-2 vjs:focus-visible:outline-blue-500',
|
||||
'vjs:group-hover/slider:opacity-100 vjs:group-focus-within/slider:opacity-100',
|
||||
'vjs:size-2.5 vjs:active:size-3 vjs:group-active/slider:size-3',
|
||||
'vjs:[&[data-orientation="horizontal"]]:hover:cursor-ew-resize',
|
||||
@@ -160,7 +157,7 @@ const styles: FrostedSkinStyles = {
|
||||
'vjs:relative vjs:px-1 vjs:py-3 vjs:rounded-full',
|
||||
),
|
||||
TooltipPopup: cn(
|
||||
'vjs:whitespace-nowrap vjs:flex vjs:flex-col vjs:rounded-full vjs:text-white vjs:text-xs vjs:@7xl/root:text-sm vjs:px-2.5 vjs:py-1',
|
||||
'vjs:whitespace-nowrap vjs:rounded-full vjs:text-white vjs:text-xs vjs:@7xl/root:text-sm vjs:px-2.5 vjs:py-1',
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ const styles: MinimalSkinStyles = {
|
||||
),
|
||||
Icon: cn('icon'),
|
||||
Button: cn(
|
||||
'vjs:group/button vjs:cursor-pointer vjs:relative vjs:shrink-0 vjs:transition vjs:select-none vjs:p-2.5 vjs:rounded-md',
|
||||
'vjs:group/button vjs:cursor-pointer vjs:relative vjs:shrink-0 vjs:transition-[color,background,outline-offset] vjs:select-none vjs:p-2.5 vjs:rounded-md',
|
||||
// Background/foreground
|
||||
'vjs:bg-transparent vjs:text-white',
|
||||
// Hover and focus states
|
||||
@@ -54,7 +54,7 @@ const styles: MinimalSkinStyles = {
|
||||
// Focus state
|
||||
'vjs:-outline-offset-2 vjs:focus-visible:outline-2 vjs:focus-visible:outline-offset-2 vjs:focus-visible:outline-white',
|
||||
// Disabled state
|
||||
'vjs:aria-disabled:grayscale vjs:aria-disabled:opacity-50 vjs:aria-disabled:cursor-not-allowed',
|
||||
'vjs:disabled:grayscale vjs:disabled:opacity-50 vjs:disabled:cursor-not-allowed',
|
||||
// Loading state
|
||||
'vjs:aria-busy:pointer-events-none vjs:aria-busy:cursor-not-allowed',
|
||||
// Expanded state
|
||||
@@ -63,11 +63,11 @@ const styles: MinimalSkinStyles = {
|
||||
ButtonGroup: cn('vjs:flex vjs:items-center vjs:gap-1.5'),
|
||||
IconButton: cn(
|
||||
'vjs:grid vjs:[&_.icon]:[grid-area:1/1]',
|
||||
'vjs:[&_.icon]:shrink-0 vjs:[&_.icon]:transition-[opacity,filter] vjs:[&_.icon]:duration-300 vjs:[&_.icon]:linear vjs:[&_.icon]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] vjs:[&_.icon]:shadow-black/40',
|
||||
'vjs:[&_.icon]:shrink-0 vjs:[&_.icon]:transition-opacity vjs:[&_.icon]:duration-150 vjs:[&_.icon]:ease-linear vjs:[&_.icon]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] vjs:[&_.icon]:shadow-black/40',
|
||||
),
|
||||
PlayButton: cn(
|
||||
'vjs:[&_.pause-icon]:opacity-100 vjs:[&_.pause-icon]:blur-none vjs:[&[data-paused]_.pause-icon]:opacity-0 vjs:[&[data-paused]_.pause-icon]:blur-xs',
|
||||
'vjs:[&_.play-icon]:opacity-0 vjs:[&_.play-icon]:blur-xs vjs:[&[data-paused]_.play-icon]:opacity-100 vjs:[&[data-paused]_.play-icon]:blur-none',
|
||||
'vjs:[&_.pause-icon]:opacity-100 vjs:[&[data-paused]_.pause-icon]:opacity-0',
|
||||
'vjs:[&_.play-icon]:opacity-0 vjs:[&[data-paused]_.play-icon]:opacity-100',
|
||||
),
|
||||
PlayIcon: cn('play-icon'),
|
||||
PauseIcon: cn('pause-icon'),
|
||||
@@ -114,23 +114,21 @@ const styles: MinimalSkinStyles = {
|
||||
TimeDisplay: cn('vjs:tabular-nums vjs:text-shadow-2xs/20'),
|
||||
DurationDisplay: cn('vjs:text-white/50 vjs:contents'),
|
||||
SliderRoot: cn(
|
||||
'vjs:flex vjs:items-center vjs:justify-center vjs:flex-1 vjs:group/slider vjs:relative vjs:rounded-sm',
|
||||
'vjs:flex vjs:items-center vjs:justify-center vjs:flex-1 vjs:group/slider vjs:relative vjs:rounded-full',
|
||||
'vjs:[&[data-orientation="horizontal"]]:h-5 vjs:[&[data-orientation="horizontal"]]:min-w-20',
|
||||
'vjs:[&[data-orientation="vertical"]]:w-5 vjs:[&[data-orientation="vertical"]]:h-18',
|
||||
// Focus state
|
||||
'vjs:-outline-offset-8 vjs:focus-visible:outline-2 vjs:focus-visible:outline-offset-8 vjs:focus-visible:outline-white',
|
||||
),
|
||||
SliderTrack: cn(
|
||||
'vjs:relative vjs:select-none vjs:rounded-full vjs:bg-white/10 vjs:transition-[height,width] vjs:ease-in-out',
|
||||
'vjs:relative vjs:select-none vjs:rounded-[inherit] vjs:bg-white/10',
|
||||
'vjs:[&[data-orientation="horizontal"]]:w-full vjs:[&[data-orientation="horizontal"]]:h-[0.1875rem]',
|
||||
'vjs:[&[data-orientation="vertical"]]:w-[0.1875rem]',
|
||||
'vjs:-outline-offset-2 vjs:group-focus-visible/slider-root:outline-2 vjs:group-focus-visible/slider-root:outline-offset-2 vjs:group-focus-visible/slider-root:outline-white',
|
||||
),
|
||||
SliderProgress: cn('vjs:bg-white vjs:rounded-[inherit]'),
|
||||
SliderPointer: cn('vjs:hidden'),
|
||||
SliderThumb: cn(
|
||||
'vjs:opacity-0 vjs:scale-70 vjs:group-hover/slider:opacity-100 vjs:group-hover/slider:scale-100 vjs:focus-visible:opacity-100 vjs:focus-visible:scale-100',
|
||||
'vjs:bg-white vjs:z-10 vjs:size-3 vjs:select-none vjs:ring vjs:ring-black/10 vjs:rounded-full vjs:shadow-sm vjs:shadow-black/15 vjs:transition-[opacity,scale] vjs:ease-out',
|
||||
'vjs:-outline-offset-2 vjs:focus-visible:outline-2 vjs:focus-visible:outline-offset-2 vjs:focus-visible:outline-amber-500',
|
||||
'vjs:[&[data-orientation="horizontal"]]:hover:cursor-ew-resize',
|
||||
'vjs:[&[data-orientation="vertical"]]:hover:cursor-ns-resize',
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user