diff --git a/packages/react/src/presets/video/minimal-skin.css b/packages/react/src/presets/video/minimal-skin.css index e90d8b31..40840be8 100644 --- a/packages/react/src/presets/video/minimal-skin.css +++ b/packages/react/src/presets/video/minimal-skin.css @@ -1,7 +1,3 @@ -.media-minimal-skin * { - box-sizing: border-box; -} - .media-minimal-skin { position: relative; isolation: isolate; @@ -15,6 +11,9 @@ -webkit-font-smoothing: auto; -moz-osx-font-smoothing: auto; } +.media-minimal-skin * { + box-sizing: border-box; +} .media-minimal-skin::after { content: ""; position: absolute; @@ -155,7 +154,7 @@ text-shadow: 0 1px 0 oklab(0 0 0 / 0.2); font-variant-numeric: tabular-nums; } -@container media-controls (width > 480px) { +@container media-controls (width > 28rem) { .media-minimal-skin .media-time-controls { flex-direction: row; } @@ -175,7 +174,7 @@ align-items: center; gap: 0.075rem; } -@container media-root (width > 640px) { +@container media-root (width > 42rem) { .media-minimal-skin .media-button-group { gap: 0.125rem; } @@ -213,7 +212,7 @@ opacity: 0.5; filter: grayscale(1); } -@container media-controls (width < 480px) { +@container media-controls (width < 28rem) { .media-minimal-skin .media-button--seek { display: none; } @@ -375,6 +374,9 @@ } /* Tooltip Component Styles */ +.media-minimal-skin .media-tooltip { + white-space: nowrap; +} .media-minimal-skin .media-tooltip-popup { color: oklab(1 0 0); padding: 0.25rem 0.5rem; @@ -397,6 +399,68 @@ } } -.media-minimal-skin .media-tooltip { - white-space: nowrap; +/* Captions */ +.media-minimal-skin .media-captions { + position: absolute; + inset: auto 1rem 1.5rem 1rem; + z-index: 20; + transition: transform 150ms ease-out; + /* The delay must account for the controls delay/duration */ + transition-delay: 600ms; + pointer-events: none; + text-wrap: balance; + font-size: 1rem; +} +@media (prefers-reduced-motion: reduce) { + .media-minimal-skin .media-captions { + transition-duration: 50ms; + } +} +.media-minimal-skin .media-captions__container { + max-width: 42ch; + margin: 0 auto; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; +} +.media-minimal-skin .media-captions__text { + display: block; + padding: 0.125rem 0.5rem; + text-shadow: + 0 0 1px oklab(0 0 0 / 0.7), + 0 0 8px oklab(0 0 0 / 0.7); + color: #fff; + text-align: center; + white-space: pre-wrap; + line-height: 1.2; +} +@media (prefers-contrast: more) { + .media-minimal-skin .media-captions__text { + text-shadow: none; + box-decoration-break: clone; + background: oklab(0 0 0 / 0.7); + } +} +.media-minimal-skin .media-captions__text > * { + display: inline; +} +@container media-root (width > 20rem) { + .media-minimal-skin .media-captions { + font-size: 1.5rem; + } +} +@container media-root (width > 48rem) { + .media-minimal-skin .media-captions { + font-size: 2rem; + } +} +@container media-root (width > 80rem) { + .media-minimal-skin .media-captions { + font-size: 2.5rem; + } +} +.media-minimal-skin .media-controls[data-visible] ~ .media-captions { + transform: translateY(-2.5rem); + transition-delay: 25ms; } diff --git a/packages/react/src/presets/video/minimal-skin.tsx b/packages/react/src/presets/video/minimal-skin.tsx index 6cdb4ad1..5305fcbc 100644 --- a/packages/react/src/presets/video/minimal-skin.tsx +++ b/packages/react/src/presets/video/minimal-skin.tsx @@ -155,6 +155,15 @@ export function MinimalVideoSkin(props: MinimalVideoSkinProps): ReactNode { + {/*
+
+ An example cue + +

Another example cue with HTML

+
+
+
*/} +
); diff --git a/packages/react/src/presets/video/skin.css b/packages/react/src/presets/video/skin.css index c23e90fe..d80290b4 100644 --- a/packages/react/src/presets/video/skin.css +++ b/packages/react/src/presets/video/skin.css @@ -1,7 +1,3 @@ -.media-default-skin * { - box-sizing: border-box; -} - .media-default-skin { position: relative; isolation: isolate; @@ -15,6 +11,9 @@ -webkit-font-smoothing: auto; -moz-osx-font-smoothing: auto; } +.media-default-skin * { + box-sizing: border-box; +} .media-default-skin::before, .media-default-skin::after { content: ""; @@ -156,12 +155,13 @@ } @media (prefers-reduced-motion: reduce) { .media-default-skin .media-controls:not([data-visible]) { + /* FIXME: Make this a custom property that we can share */ transition-duration: 100ms; filter: blur(0); scale: 1; } } -@container media-root (width > 640px) { +@container media-root (width > 42rem) { .media-default-skin .media-controls { padding: 0.25rem; gap: 0.125rem; @@ -184,7 +184,7 @@ .media-default-skin .media-time .media-time__value:first-child { display: none; } -@container media-time (width > 240px) { +@container media-time (width > 18rem) { .media-default-skin .media-time .media-time__value:first-child { display: block; } @@ -224,7 +224,7 @@ opacity: 0.5; filter: grayscale(1); } -@container media-controls (width < 480px) { +@container media-controls (width < 28rem) { .media-default-skin .media-button--seek { display: none; } @@ -388,6 +388,9 @@ } /* Tooltip Component Styles */ +.media-default-skin .media-tooltip { + white-space: nowrap; +} .media-default-skin .media-tooltip-popup { color: oklab(1 0 0); padding: 0.25rem 0.625rem; @@ -395,6 +398,68 @@ font-size: 0.75rem; } -.media-default-skin .media-tooltip { - white-space: nowrap; +/* Captions */ +.media-default-skin .media-captions { + position: absolute; + inset: auto 1rem 1.5rem 1rem; + z-index: 20; + transition: transform 150ms ease-out; + /* The delay must account for the controls delay/duration */ + transition-delay: 600ms; + pointer-events: none; + text-wrap: balance; + font-size: 1rem; +} +@media (prefers-reduced-motion: reduce) { + .media-default-skin .media-captions { + transition-duration: 50ms; + } +} +.media-default-skin .media-captions__container { + max-width: 42ch; + margin: 0 auto; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; +} +.media-default-skin .media-captions__text { + display: block; + padding: 0.125rem 0.5rem; + text-shadow: + 0 0 1px oklab(0 0 0 / 0.7), + 0 0 8px oklab(0 0 0 / 0.7); + color: #fff; + text-align: center; + white-space: pre-wrap; + line-height: 1.2; +} +@media (prefers-contrast: more) { + .media-default-skin .media-captions__text { + text-shadow: none; + box-decoration-break: clone; + background: oklab(0 0 0 / 0.7); + } +} +.media-default-skin .media-captions__text > * { + display: inline; +} +@container media-root (width > 20rem) { + .media-default-skin .media-captions { + font-size: 1.5rem; + } +} +@container media-root (width > 48rem) { + .media-default-skin .media-captions { + font-size: 2rem; + } +} +@container media-root (width > 80rem) { + .media-default-skin .media-captions { + font-size: 2.5rem; + } +} +.media-default-skin .media-controls[data-visible] ~ .media-captions { + transform: translateY(-3rem); + transition-delay: 25ms; } diff --git a/packages/react/src/presets/video/skin.tsx b/packages/react/src/presets/video/skin.tsx index 78f3da68..7e14fec0 100644 --- a/packages/react/src/presets/video/skin.tsx +++ b/packages/react/src/presets/video/skin.tsx @@ -149,6 +149,15 @@ export function VideoSkin(props: VideoSkinProps): ReactNode { /> + {/*
+
+ An example cue + +

Another example cue with HTML

+
+
+
*/} +
);