mirror of
https://github.com/zoriya/v10.git
synced 2026-08-12 00:49:29 +00:00
feat(react): add Tailwind v4 compiled CSS for skins with vjs prefix (#114)
Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Darius Cepulis <dcepulis@mux.com>
This commit is contained in:
co-authored by
Claude
Darius Cepulis
parent
0a4902623d
commit
92b82e94f9
@@ -17,7 +17,6 @@ lerna-debug.log*
|
||||
# Build & Generated Outputs
|
||||
# -------------------------
|
||||
dist/
|
||||
build/
|
||||
lib/
|
||||
out/
|
||||
*.tsbuildinfo
|
||||
|
||||
@@ -2,15 +2,17 @@ import type { ChangeEventHandler } from 'react';
|
||||
|
||||
import { FrostedSkin, MediaProvider, MinimalSkin, Video } from '@vjs-10/react';
|
||||
import { FullscreenEnterAltIcon, FullscreenExitAltIcon } from '@vjs-10/react-icons';
|
||||
import clsx from 'clsx';
|
||||
|
||||
// import FrostedSkin from './skins/frosted/FrostedSkin';
|
||||
// import MinimalSkin from './skins/toasted/MinimalSkin';
|
||||
|
||||
import clsx from 'clsx';
|
||||
// NOTE: Commented out imports are for testing locally/externally defined skins.
|
||||
// import { MediaProvider, Video } from '@vjs-10/react';
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useFullscreen } from './hooks/useFullscreen';
|
||||
import '@vjs-10/react/skins/frosted.css';
|
||||
import '@vjs-10/react/skins/minimal.css';
|
||||
import './globals.css';
|
||||
|
||||
const skins = [
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
@import 'tailwindcss';
|
||||
|
||||
/* TODO: Documentation for how this will work in the wild. */
|
||||
@source "../../../packages/react";
|
||||
|
||||
@theme {
|
||||
--font-sans:
|
||||
InterVariable, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||
|
||||
@@ -2,6 +2,9 @@ import { StrictMode } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import App from './App';
|
||||
import '@vjs-10/react/skins/frosted.css';
|
||||
|
||||
import '@vjs-10/react/skins/minimal.css';
|
||||
|
||||
import './globals.css';
|
||||
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-disable no-console */
|
||||
|
||||
/**
|
||||
* Build Styles Script
|
||||
*
|
||||
* This unified script handles the complete CSS build process for skins:
|
||||
*
|
||||
* 1. COMPILATION: Runs Tailwind CLI to compile CSS files
|
||||
* - preflight.css (browser resets)
|
||||
* - frosted.css (frosted skin)
|
||||
* - minimal.css (minimal skin)
|
||||
*
|
||||
* 2. SCOPING: Scopes preflight selectors to `.vjs` class to prevent global resets
|
||||
* - Transforms `* { margin: 0 }` → `.vjs * { margin: 0 }`
|
||||
* - Special cases like `html`, `body`, `:root` → `.vjs`
|
||||
*
|
||||
* 3. CONCATENATION: Prepends scoped preflight to each skin CSS file
|
||||
* - frosted.css = scoped-preflight + frosted styles
|
||||
* - minimal.css = scoped-preflight + minimal styles
|
||||
* - Deletes standalone preflight.css (no longer needed)
|
||||
*
|
||||
* Why scope preflight?
|
||||
* - Tailwind's preflight resets affect ALL elements globally
|
||||
* - Scoping to `.vjs` ensures resets only apply inside video player containers
|
||||
*
|
||||
* Why concatenate?
|
||||
* - Users only need to import one CSS file per skin
|
||||
* - Simpler API: import '@vjs-10/react/skins/frosted.css'
|
||||
*/
|
||||
|
||||
import { execSync } from 'node:child_process';
|
||||
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import process from 'node:process';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import postcss from 'postcss';
|
||||
import prefixSelector from 'postcss-prefix-selector';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const rootDir = join(__dirname, '..');
|
||||
|
||||
const preflightFile = 'dist/skins/preflight.css';
|
||||
const frostedFile = 'dist/skins/frosted.css';
|
||||
const minimalFile = 'dist/skins/minimal.css';
|
||||
|
||||
export default async function buildStyles() {
|
||||
console.log('🎨 Building skin styles...');
|
||||
|
||||
try {
|
||||
// ============================================================================
|
||||
// STEP 1: Compile CSS files with Tailwind CLI
|
||||
// ============================================================================
|
||||
console.log(' → Compiling CSS with Tailwind...');
|
||||
|
||||
// Create output directory
|
||||
const execOpts = { cwd: rootDir, stdio: 'inherit', encoding: 'utf8' };
|
||||
const skinsDir = join(rootDir, 'dist', 'skins');
|
||||
|
||||
mkdirSync(skinsDir, { recursive: true });
|
||||
|
||||
// Compile preflight (browser resets)
|
||||
execSync(
|
||||
'pnpm exec tailwindcss -i src/skins/preflight.css -o dist/skins/preflight.css --minify',
|
||||
execOpts,
|
||||
);
|
||||
|
||||
// Compile frosted skin
|
||||
execSync(
|
||||
'pnpm exec tailwindcss -i src/skins/frosted/frosted-skin.css -o dist/skins/frosted.css --minify',
|
||||
execOpts,
|
||||
);
|
||||
|
||||
// Compile minimal skin
|
||||
execSync(
|
||||
'pnpm exec tailwindcss -i src/skins/minimal/minimal-skin.css -o dist/skins/minimal.css --minify',
|
||||
execOpts,
|
||||
);
|
||||
|
||||
// Verify all CSS files were created
|
||||
const preflightPath = join(rootDir, preflightFile);
|
||||
const frostedPath = join(rootDir, frostedFile);
|
||||
const minimalPath = join(rootDir, minimalFile);
|
||||
|
||||
if (!existsSync(preflightPath)) {
|
||||
throw new Error(`Tailwind failed to create ${preflightFile}`);
|
||||
}
|
||||
if (!existsSync(frostedPath)) {
|
||||
throw new Error(`Tailwind failed to create ${frostedFile}`);
|
||||
}
|
||||
if (!existsSync(minimalPath)) {
|
||||
throw new Error(`Tailwind failed to create ${minimalFile}`);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// STEP 2: Scope preflight CSS to .vjs
|
||||
// ============================================================================
|
||||
console.log(' → Scoping preflight selectors to .vjs...');
|
||||
|
||||
const preflightCss = readFileSync(preflightPath, 'utf-8');
|
||||
|
||||
// Use PostCSS with postcss-prefix-selector plugin to transform all selectors
|
||||
const result = await postcss([
|
||||
prefixSelector({
|
||||
prefix: '.vjs',
|
||||
transform(prefix, selector, prefixedSelector) {
|
||||
// Special case transformations:
|
||||
// - `html`, `body`, `:root` should become just `.vjs` (not `.vjs html`)
|
||||
if (selector === 'body' || selector === 'html' || selector === ':root') {
|
||||
return prefix;
|
||||
} else if (selector === ':host') {
|
||||
// Keep :host as-is (for web components)
|
||||
return selector;
|
||||
} else {
|
||||
// All other selectors: prepend .vjs
|
||||
return prefixedSelector;
|
||||
}
|
||||
},
|
||||
}),
|
||||
]).process(preflightCss, { from: preflightFile, to: preflightFile });
|
||||
|
||||
// Clean up any duplicate .vjs classes that may have been generated
|
||||
const scopedPreflight = result.css.replace(/(\.vjs\s+)+/g, '.vjs ');
|
||||
|
||||
// ============================================================================
|
||||
// STEP 3: Concatenate scoped preflight into each skin
|
||||
// ============================================================================
|
||||
console.log(' → Concatenating preflight into frosted.css...');
|
||||
|
||||
const frostedCss = readFileSync(frostedPath, 'utf-8');
|
||||
const frostedWithPreflight = `${scopedPreflight}\n${frostedCss}`;
|
||||
writeFileSync(frostedPath, frostedWithPreflight, 'utf-8');
|
||||
|
||||
console.log(' → Concatenating preflight into minimal.css...');
|
||||
|
||||
const minimalCss = readFileSync(minimalPath, 'utf-8');
|
||||
const minimalWithPreflight = `${scopedPreflight}\n${minimalCss}`;
|
||||
writeFileSync(minimalPath, minimalWithPreflight, 'utf-8');
|
||||
|
||||
// ============================================================================
|
||||
// STEP 4: Clean up - delete standalone preflight.css
|
||||
// ============================================================================
|
||||
console.log(' → Removing standalone preflight.css...');
|
||||
unlinkSync(preflightPath);
|
||||
|
||||
console.log('✅ Skin styles built successfully');
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to build styles:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,9 @@
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"./skins/frosted.css": "./dist/skins/frosted.css",
|
||||
"./skins/minimal.css": "./dist/skins/minimal.css"
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.js",
|
||||
@@ -25,7 +27,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"build:watch": "tsdown --watch --silent",
|
||||
"build:watch": "tsdown --watch ./src --silent",
|
||||
"dev": "pnpm run build:watch",
|
||||
"test": "echo \"No tests yet\"",
|
||||
"clean": "rm -rf dist"
|
||||
@@ -43,8 +45,12 @@
|
||||
"@vjs-10/react-media-store": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/cli": "^4.1.0",
|
||||
"@types/react": "^18.0.0",
|
||||
"postcss": "^8.4.49",
|
||||
"postcss-prefix-selector": "^1.16.1",
|
||||
"react": "^18.0.0",
|
||||
"tailwindcss": "^4.1.13",
|
||||
"tsdown": "^0.15.9",
|
||||
"typescript": "^5.9.2"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
@layer theme, base, components, utilities;
|
||||
@import 'tailwindcss/theme.css' layer(theme) prefix(vjs);
|
||||
@import 'tailwindcss/utilities.css' layer(utilities) prefix(vjs);
|
||||
|
||||
/* Custom variants used by the frosted skin */
|
||||
@custom-variant reduced-transparency @media (prefers-reduced-transparency: reduce);
|
||||
@@ -11,171 +11,172 @@ function cn(...classes: (string | undefined)[]): string {
|
||||
|
||||
const styles: FrostedSkinStyles = {
|
||||
MediaContainer: cn(
|
||||
'relative isolate @container/root group/root overflow-clip',
|
||||
'vjs', // scope preflight
|
||||
'vjs:relative vjs:isolate vjs:@container/root vjs:group/root vjs:overflow-clip',
|
||||
// Base typography
|
||||
'text-[0.8125rem]', // 13px
|
||||
'vjs:text-[0.8125rem]', // 13px
|
||||
// Prevent rounded corners in fullscreen.
|
||||
'[&:fullscreen]:rounded-none [&:fullscreen]:[&_video]:h-full [&:fullscreen]:[&_video]:w-full',
|
||||
'vjs:[&:fullscreen]:rounded-none vjs:[&:fullscreen]:[&_video]:h-full vjs:[&:fullscreen]:[&_video]:w-full',
|
||||
// Fancy borders.
|
||||
'after:absolute after:inset-0 after:ring-black/10 after:ring-1 dark:after:ring-white/10 after:ring-inset after:z-10 after:pointer-events-none after:rounded-[inherit]',
|
||||
'before:absolute before:inset-px before:rounded-[inherit] before:ring-white/15 before:ring-1 before:ring-inset before:z-10 before:pointer-events-none dark:before:ring-0',
|
||||
'vjs:after:absolute vjs:after:inset-0 vjs:after:ring-black/10 vjs:after:ring-1 vjs:dark:after:ring-white/10 vjs:after:ring-inset vjs:after:z-10 vjs:after:pointer-events-none vjs:after:rounded-[inherit]',
|
||||
'vjs:before:absolute vjs:before:inset-px vjs:before:rounded-[inherit] vjs:before:ring-white/15 vjs:before:ring-1 vjs:before:ring-inset vjs:before:z-10 vjs:before:pointer-events-none vjs:dark:before:ring-0',
|
||||
// Ensure the nested video inherits the radius.
|
||||
'[&_video]:rounded-[inherit] [&_video]:w-full [&_video]:h-auto',
|
||||
'vjs:[&_video]:rounded-[inherit] vjs:[&_video]:w-full vjs:[&_video]:h-auto',
|
||||
),
|
||||
Overlay: cn(
|
||||
'opacity-0 delay-500 rounded-[inherit] absolute inset-0 pointer-events-none bg-gradient-to-t from-black/50 via-black/20 to-transparent transition-opacity backdrop-saturate-150 backdrop-brightness-90',
|
||||
'vjs:opacity-0 vjs:delay-500 vjs:rounded-[inherit] vjs:absolute vjs:inset-0 vjs:pointer-events-none vjs:bg-gradient-to-t vjs:from-black/50 vjs:via-black/20 vjs:to-transparent vjs:transition-opacity vjs:backdrop-saturate-150 vjs:backdrop-brightness-90',
|
||||
// Hide when playing (for now).
|
||||
// FIXME: This is crude temporary logic, we’ll improve it later I guess with a [data-show-controls] attribute or something?
|
||||
'has-[+.controls_[data-paused]]:opacity-100 has-[+.controls_[data-paused]]:delay-0',
|
||||
'has-[+.controls_[aria-expanded="true"]]:opacity-100 has-[+.controls_[aria-expanded="true"]]:delay-0',
|
||||
'group-hover/root:opacity-100 group-hover/root:delay-0',
|
||||
// FIXME: This is crude temporary logic, we'll improve it later I guess with a [data-show-controls] attribute or something?
|
||||
'vjs:has-[+.controls_[data-paused]]:opacity-100 vjs:has-[+.controls_[data-paused]]:delay-0',
|
||||
'vjs:has-[+.controls_[aria-expanded="true"]]:opacity-100 vjs:has-[+.controls_[aria-expanded="true"]]:delay-0',
|
||||
'vjs:group-hover/root:opacity-100 vjs:group-hover/root:delay-0',
|
||||
),
|
||||
Controls: cn(
|
||||
'controls', // FIXME: Temporary className hook for above logic in the overlay. Can be removed once have a proper way to handle controls visibility.
|
||||
'@container/controls absolute inset-x-3 bottom-3 rounded-full flex items-center p-1 ring ring-white/10 ring-inset gap-0.5 text-white',
|
||||
'shadow-sm shadow-black/15',
|
||||
'vjs:@container/controls vjs:absolute vjs:inset-x-3 vjs:bottom-3 vjs:rounded-full vjs:flex vjs:items-center vjs:p-1 vjs:ring vjs:ring-white/10 vjs:ring-inset vjs:gap-0.5 vjs:text-white',
|
||||
'vjs:shadow-sm vjs:shadow-black/15',
|
||||
// Background
|
||||
'bg-white/10 backdrop-blur-3xl backdrop-saturate-150 backdrop-brightness-90',
|
||||
'vjs:bg-white/10 vjs:backdrop-blur-3xl vjs:backdrop-saturate-150 vjs:backdrop-brightness-90',
|
||||
// Animation
|
||||
'transition will-change-transform origin-bottom ease-out',
|
||||
'vjs:transition vjs:will-change-transform vjs:origin-bottom vjs:ease-out',
|
||||
// FIXME: Temporary hide/show logic
|
||||
'scale-90 opacity-0 delay-500 duration-300',
|
||||
'has-[[data-paused]]:scale-100 has-[[data-paused]]:opacity-100 has-[[data-paused]]:delay-0',
|
||||
'has-[[aria-expanded="true"]]:scale-100 has-[[aria-expanded="true"]]:opacity-100 has-[[aria-expanded="true"]]:delay-0',
|
||||
'group-hover/root:scale-100 group-hover/root:opacity-100 group-hover/root:delay-0',
|
||||
'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',
|
||||
// Border to enhance contrast on lighter videos
|
||||
'after:absolute after:inset-0 after:ring after:rounded-[inherit] after:ring-black/15 after:pointer-events-none after:z-10',
|
||||
'vjs:after:absolute vjs:after:inset-0 vjs:after:ring vjs:after:rounded-[inherit] vjs:after:ring-black/15 vjs:after:pointer-events-none vjs:after:z-10',
|
||||
// Reduced transparency for users with preference
|
||||
// XXX: This requires a Tailwind custom variant (see 1 below)
|
||||
'reduced-transparency:bg-black/70 reduced-transparency:ring-black reduced-transparency:after:ring-white/20',
|
||||
'vjs:reduced-transparency:bg-black/70 vjs:reduced-transparency:ring-black vjs:reduced-transparency:after:ring-white/20',
|
||||
// High contrast mode
|
||||
'contrast-more:bg-black/90 contrast-more:ring-black contrast-more:after:ring-white/20',
|
||||
'vjs:contrast-more:bg-black/90 vjs:contrast-more:ring-black vjs:contrast-more:after:ring-white/20',
|
||||
),
|
||||
Icon: cn('icon'),
|
||||
Button: cn(
|
||||
'group/button cursor-pointer relative shrink-0 transition select-none p-2 rounded-full',
|
||||
'vjs:group/button vjs:cursor-pointer vjs:relative vjs:shrink-0 vjs:transition vjs:select-none vjs:p-2 vjs:rounded-full',
|
||||
// Background/foreground
|
||||
'bg-transparent text-white/90',
|
||||
'vjs:bg-transparent vjs:text-white/90',
|
||||
// Hover and focus states
|
||||
'hover:no-underline hover:bg-white/10 hover:text-white focus-visible:no-underline focus-visible:bg-white/10 focus-visible:text-white',
|
||||
'vjs:hover:no-underline vjs:hover:bg-white/10 vjs:hover:text-white vjs:focus-visible:no-underline vjs:focus-visible:bg-white/10 vjs:focus-visible:text-white',
|
||||
// Focus state
|
||||
'-outline-offset-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500',
|
||||
'vjs:-outline-offset-2 vjs:focus-visible:outline-2 vjs:focus-visible:outline-offset-2 vjs:focus-visible:outline-blue-500',
|
||||
// Disabled state
|
||||
'aria-disabled:grayscale aria-disabled:opacity-50 aria-disabled:cursor-not-allowed',
|
||||
'vjs:aria-disabled:grayscale vjs:aria-disabled:opacity-50 vjs:aria-disabled:cursor-not-allowed',
|
||||
// Loading state
|
||||
'aria-busy:pointer-events-none aria-busy:cursor-not-allowed',
|
||||
'vjs:aria-busy:pointer-events-none vjs:aria-busy:cursor-not-allowed',
|
||||
// Expanded state
|
||||
'aria-expanded:bg-white/10 aria-expanded:text-white',
|
||||
'vjs:aria-expanded:bg-white/10 vjs:aria-expanded:text-white',
|
||||
// Pressed state
|
||||
'active:scale-95',
|
||||
'vjs:active:scale-95',
|
||||
),
|
||||
IconButton: cn(
|
||||
'grid [&_.icon]:[grid-area:1/1]',
|
||||
'[&_.icon]:shrink-0 [&_.icon]:transition-opacity [&_.icon]:duration-300 [&_.icon]:ease-out [&_.icon]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] [&_.icon]:shadow-black/25',
|
||||
'vjs:grid vjs:[&_.icon]:[grid-area:1/1]',
|
||||
'vjs:[&_.icon]:shrink-0 vjs:[&_.icon]:transition-opacity vjs:[&_.icon]:duration-300 vjs:[&_.icon]:ease-out vjs:[&_.icon]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] vjs:[&_.icon]:shadow-black/25',
|
||||
),
|
||||
PlayButton: cn(
|
||||
'[&_.pause-icon]:opacity-100 [&[data-paused]_.pause-icon]:opacity-0',
|
||||
'[&_.play-icon]:opacity-0 [&[data-paused]_.play-icon]:opacity-100',
|
||||
'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'),
|
||||
TooltipPopup: cn(
|
||||
'whitespace-nowrap flex origin-[var(--transform-origin)] flex-col rounded-md text-white text-xs @7xl/root:text-sm px-2 py-1',
|
||||
'vjs:whitespace-nowrap vjs:flex vjs:origin-[var(--transform-origin)] vjs:flex-col vjs:rounded-md vjs:text-white vjs:text-xs vjs:@7xl/root:text-sm vjs:px-2 vjs:py-1',
|
||||
// Background
|
||||
'bg-white/10 backdrop-blur-3xl backdrop-saturate-150 backdrop-brightness-90',
|
||||
'vjs:bg-white/10 vjs:backdrop-blur-3xl vjs:backdrop-saturate-150 vjs:backdrop-brightness-90',
|
||||
// Animation
|
||||
'transition-[transform,scale,opacity] data-[ending-style]:scale-90 data-[ending-style]:opacity-0 data-[instant]:duration-0 data-[starting-style]:scale-90 data-[starting-style]:opacity-0',
|
||||
'vjs:transition-[transform,scale,opacity] vjs:data-[ending-style]:scale-90 vjs:data-[ending-style]:opacity-0 vjs:data-[instant]:duration-0 vjs:data-[starting-style]:scale-90 vjs:data-[starting-style]:opacity-0',
|
||||
// Ring
|
||||
'ring-1 ring-white/10 ring-inset',
|
||||
'vjs:ring-1 vjs:ring-white/10 vjs:ring-inset',
|
||||
// Border to enhance contrast on lighter videos
|
||||
'after:absolute after:inset-0 after:ring after:rounded-[inherit] after:ring-black/15 after:pointer-events-none',
|
||||
'vjs:after:absolute vjs:after:inset-0 vjs:after:ring vjs:after:rounded-[inherit] vjs:after:ring-black/15 vjs:after:pointer-events-none',
|
||||
),
|
||||
PlayTooltipPopup: cn(
|
||||
'[&_.pause-tooltip]:inline [&[data-paused]_.pause-tooltip]:hidden',
|
||||
'[&_.play-tooltip]:hidden [&[data-paused]_.play-tooltip]:inline',
|
||||
'vjs:[&_.pause-tooltip]:inline vjs:[&[data-paused]_.pause-tooltip]:hidden',
|
||||
'vjs:[&_.play-tooltip]:hidden vjs:[&[data-paused]_.play-tooltip]:inline',
|
||||
),
|
||||
PlayTooltip: cn('play-tooltip'),
|
||||
PauseTooltip: cn('pause-tooltip'),
|
||||
MuteButton: cn(
|
||||
'[&_.icon]:opacity-0',
|
||||
'[&[data-volume-level="high"]_.volume-high-icon]:opacity-100',
|
||||
'[&[data-volume-level="medium"]_.volume-low-icon]:opacity-100',
|
||||
'[&[data-volume-level="low"]_.volume-low-icon]:opacity-100',
|
||||
'[&[data-volume-level="off"]_.volume-off-icon]:opacity-100',
|
||||
'vjs:[&_.icon]:opacity-0',
|
||||
'vjs:[&[data-volume-level="high"]_.volume-high-icon]:opacity-100',
|
||||
'vjs:[&[data-volume-level="medium"]_.volume-low-icon]:opacity-100',
|
||||
'vjs:[&[data-volume-level="low"]_.volume-low-icon]:opacity-100',
|
||||
'vjs:[&[data-volume-level="off"]_.volume-off-icon]:opacity-100',
|
||||
),
|
||||
VolumeHighIcon: cn('volume-high-icon'),
|
||||
VolumeLowIcon: cn('volume-low-icon'),
|
||||
VolumeOffIcon: cn('volume-off-icon'),
|
||||
FullscreenButton: cn(
|
||||
'[&_.fullscreen-enter-icon]:opacity-100 [&[data-fullscreen]_.fullscreen-enter-icon]:opacity-0',
|
||||
'[&_.fullscreen-exit-icon]:opacity-0 [&[data-fullscreen]_.fullscreen-exit-icon]:opacity-100',
|
||||
'[&_path]:transition-transform ease-out',
|
||||
'vjs:[&_.fullscreen-enter-icon]:opacity-100 vjs:[&[data-fullscreen]_.fullscreen-enter-icon]:opacity-0',
|
||||
'vjs:[&_.fullscreen-exit-icon]:opacity-0 vjs:[&[data-fullscreen]_.fullscreen-exit-icon]:opacity-100',
|
||||
'vjs:[&_path]:transition-transform vjs:ease-out',
|
||||
),
|
||||
FullscreenEnterIcon: cn(
|
||||
'fullscreen-enter-icon',
|
||||
'group-hover/button:[&_.arrow-1]:-translate-x-px group-hover/button:[&_.arrow-1]:-translate-y-px',
|
||||
'group-hover/button:[&_.arrow-2]:translate-x-px group-hover/button:[&_.arrow-2]:translate-y-px',
|
||||
'vjs:group-hover/button:[&_.arrow-1]:-translate-x-px vjs:group-hover/button:[&_.arrow-1]:-translate-y-px',
|
||||
'vjs:group-hover/button:[&_.arrow-2]:translate-x-px vjs:group-hover/button:[&_.arrow-2]:translate-y-px',
|
||||
),
|
||||
FullscreenExitIcon: cn(
|
||||
'fullscreen-exit-icon',
|
||||
'[&_.arrow-1]:-translate-x-px [&_.arrow-1]:-translate-y-px',
|
||||
'[&_.arrow-2]:translate-x-px [&_.arrow-2]:translate-y-px',
|
||||
'group-hover/button:[&_.arrow-1]:translate-0',
|
||||
'group-hover/button:[&_.arrow-2]:translate-0',
|
||||
'vjs:[&_.arrow-1]:-translate-x-px vjs:[&_.arrow-1]:-translate-y-px',
|
||||
'vjs:[&_.arrow-2]:translate-x-px vjs:[&_.arrow-2]:translate-y-px',
|
||||
'vjs:group-hover/button:[&_.arrow-1]:translate-0',
|
||||
'vjs:group-hover/button:[&_.arrow-2]:translate-0',
|
||||
),
|
||||
FullscreenTooltipPopup: cn(
|
||||
'[&_.fullscreen-enter-tooltip]:inline [&[data-fullscreen]_.fullscreen-enter-tooltip]:hidden',
|
||||
'[&_.fullscreen-exit-tooltip]:hidden [&[data-fullscreen]_.fullscreen-exit-tooltip]:inline',
|
||||
'vjs:[&_.fullscreen-enter-tooltip]:inline vjs:[&[data-fullscreen]_.fullscreen-enter-tooltip]:hidden',
|
||||
'vjs:[&_.fullscreen-exit-tooltip]:hidden vjs:[&[data-fullscreen]_.fullscreen-exit-tooltip]:inline',
|
||||
),
|
||||
FullscreenEnterTooltip: cn('fullscreen-enter-tooltip'),
|
||||
FullscreenExitTooltip: cn('fullscreen-exit-tooltip'),
|
||||
TimeControls: cn('flex-1 flex items-center gap-3 px-1.5'),
|
||||
TimeDisplay: cn('tabular-nums text-shadow-2xs/25'),
|
||||
TimeControls: cn('vjs:flex-1 vjs:flex vjs:items-center vjs:gap-3 vjs:px-1.5'),
|
||||
TimeDisplay: cn('vjs:tabular-nums vjs:text-shadow-2xs/25'),
|
||||
SliderRoot: cn(
|
||||
'flex items-center justify-center flex-1 group/slider relative rounded-full',
|
||||
'[&[data-orientation="horizontal"]]:h-5 [&[data-orientation="horizontal"]]:min-w-20',
|
||||
'[&[data-orientation="vertical"]]:w-5 [&[data-orientation="vertical"]]:h-20',
|
||||
'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-20',
|
||||
// Focus state
|
||||
'focus-visible:outline-2 focus-visible:outline-blue-500',
|
||||
'vjs:focus-visible:outline-2 vjs:focus-visible:outline-blue-500',
|
||||
),
|
||||
SliderTrack: cn(
|
||||
'w-full relative select-none rounded-full bg-white/20 ring-1 ring-black/5',
|
||||
'[&[data-orientation="horizontal"]]:h-1',
|
||||
'[&[data-orientation="vertical"]]:w-1',
|
||||
'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:[&[data-orientation="vertical"]]:w-1',
|
||||
),
|
||||
SliderProgress: cn('bg-white rounded-[inherit]'),
|
||||
SliderProgress: cn('vjs:bg-white vjs:rounded-[inherit]'),
|
||||
// TODO: Work out what we want to do here.
|
||||
SliderPointer: cn('bg-white/20 rounded-[inherit]'),
|
||||
SliderPointer: cn('vjs:bg-white/20 vjs:rounded-[inherit]'),
|
||||
SliderThumb: cn(
|
||||
'bg-white z-10 select-none ring ring-black/10 rounded-full shadow-sm shadow-black/15',
|
||||
'opacity-0 transition-[opacity,height,width] ease-in-out',
|
||||
'-outline-offset-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500',
|
||||
'group-hover/slider:opacity-100 group-focus-within/slider:opacity-100',
|
||||
'size-2.5 active:size-3 group-active/slider:size-3',
|
||||
'[&[data-orientation="horizontal"]]:hover:cursor-ew-resize',
|
||||
'[&[data-orientation="vertical"]]:hover:cursor-ns-resize',
|
||||
'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',
|
||||
'vjs:[&[data-orientation="vertical"]]:hover:cursor-ns-resize',
|
||||
),
|
||||
TimeSliderRoot: cn(
|
||||
// Focus state
|
||||
'-outline-offset-8 focus-visible:outline-offset-8',
|
||||
'vjs:-outline-offset-8 vjs:focus-visible:outline-offset-8',
|
||||
),
|
||||
VolumeSliderRoot: cn(
|
||||
// Focus state
|
||||
'-outline-offset-4 focus-visible:outline-offset-4',
|
||||
'vjs:-outline-offset-4 vjs:focus-visible:outline-offset-4',
|
||||
),
|
||||
PopoverPopup: cn(
|
||||
'relative px-1.5 py-3.5 rounded-full',
|
||||
'bg-white/10 backdrop-blur-3xl backdrop-saturate-150 backdrop-brightness-90',
|
||||
'ring ring-white/10 ring-inset shadow-sm shadow-black/15',
|
||||
'vjs:relative vjs:px-1.5 vjs:py-3.5 vjs:rounded-full',
|
||||
'vjs:bg-white/10 vjs:backdrop-blur-3xl vjs:backdrop-saturate-150 vjs:backdrop-brightness-90',
|
||||
'vjs:ring vjs:ring-white/10 vjs:ring-inset vjs:shadow-sm vjs:shadow-black/15',
|
||||
// Animation
|
||||
'transition-[transform,scale,opacity] data-[ending-style]:scale-90 data-[ending-style]:opacity-0 data-[instant]:duration-0 data-[starting-style]:scale-90 data-[starting-style]:opacity-0',
|
||||
'vjs:transition-[transform,scale,opacity] vjs:data-[ending-style]:scale-90 vjs:data-[ending-style]:opacity-0 vjs:data-[instant]:duration-0 vjs:data-[starting-style]:scale-90 vjs:data-[starting-style]:opacity-0',
|
||||
// Border to enhance contrast on lighter videos
|
||||
'after:absolute after:inset-0 after:ring after:rounded-[inherit] after:ring-black/15 after:pointer-events-none after:z-10',
|
||||
'vjs:after:absolute vjs:after:inset-0 vjs:after:ring vjs:after:rounded-[inherit] vjs:after:ring-black/15 vjs:after:pointer-events-none vjs:after:z-10',
|
||||
// Reduced transparency for users with preference
|
||||
// XXX: This requires a Tailwind custom variant (see 1 below)
|
||||
'reduced-transparency:bg-black/70 reduced-transparency:ring-black reduced-transparency:after:ring-white/20',
|
||||
'vjs:reduced-transparency:bg-black/70 vjs:reduced-transparency:ring-black vjs:reduced-transparency:after:ring-white/20',
|
||||
// High contrast mode
|
||||
'contrast-more:bg-black/90 contrast-more:ring-black contrast-more:after:ring-white/20',
|
||||
'vjs:contrast-more:bg-black/90 vjs:contrast-more:ring-black vjs:contrast-more:after:ring-white/20',
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
@layer theme, base, components, utilities;
|
||||
@import 'tailwindcss/theme.css' layer(theme) prefix(vjs);
|
||||
@import 'tailwindcss/utilities.css' layer(utilities) prefix(vjs);
|
||||
@@ -11,138 +11,139 @@ function cn(...classes: (string | undefined)[]): string {
|
||||
|
||||
const styles: MinimalSkinStyles = {
|
||||
MediaContainer: cn(
|
||||
'relative isolate @container/root group/root overflow-clip bg-black',
|
||||
'vjs', // scope preflight
|
||||
'vjs:relative vjs:isolate vjs:@container/root vjs:group/root vjs:overflow-clip vjs:bg-black',
|
||||
// Base typography
|
||||
'text-[0.8125rem]', // 13px
|
||||
'vjs:text-[0.8125rem]', // 13px
|
||||
// 'ring-1 ring-inset ring-black/10 dark:ring-white/10',
|
||||
'after:absolute after:inset-0 after:ring-black/10 after:ring-1 dark:after:ring-white/10 after:ring-inset after:z-10 after:pointer-events-none after:rounded-[inherit]',
|
||||
'vjs:after:absolute vjs:after:inset-0 vjs:after:ring-black/10 vjs:after:ring-1 vjs:dark:after:ring-white/10 vjs:after:ring-inset vjs:after:z-10 vjs:after:pointer-events-none vjs:after:rounded-[inherit]',
|
||||
// Prevent rounded corners in fullscreen.
|
||||
'[&:fullscreen]:rounded-none [&:fullscreen]:[&_video]:h-full [&:fullscreen]:[&_video]:w-full',
|
||||
'vjs:[&:fullscreen]:rounded-none vjs:[&:fullscreen]:[&_video]:h-full vjs:[&:fullscreen]:[&_video]:w-full',
|
||||
// Ensure the nested video inherits the radius.
|
||||
'[&_video]:rounded-[inherit] [&_video]:w-full [&_video]:h-auto',
|
||||
'vjs:[&_video]:rounded-[inherit] vjs:[&_video]:w-full vjs:[&_video]:h-auto',
|
||||
),
|
||||
Overlay: cn(
|
||||
'absolute inset-0 rounded-[inherit]',
|
||||
'bg-gradient-to-t from-black/70 via-black/50 via-[120px] to-transparent',
|
||||
'opacity-0 delay-500 duration-300',
|
||||
'vjs:absolute vjs:inset-0 vjs:rounded-[inherit]',
|
||||
'vjs:bg-gradient-to-t vjs:from-black/70 vjs:via-black/50 vjs:via-[120px] vjs:to-transparent',
|
||||
'vjs:opacity-0 vjs:delay-500 vjs:duration-300',
|
||||
// FIXME: Temporary hide/show logic
|
||||
'has-[+.controls_[data-paused]]:opacity-100 has-[+.controls_[data-paused]]:delay-0 has-[+.controls_[data-paused]]:duration-75',
|
||||
'has-[+.controls_[aria-expanded="true"]]:opacity-100 has-[+.controls_[aria-expanded="true"]]:delay-0 has-[+.controls_[aria-expanded="true"]]:duration-75',
|
||||
'group-hover/root:opacity-100 group-hover/root:delay-0 group-hover/root:duration-75',
|
||||
'vjs:has-[+.controls_[data-paused]]:opacity-100 vjs:has-[+.controls_[data-paused]]:delay-0 vjs:has-[+.controls_[data-paused]]:duration-75',
|
||||
'vjs:has-[+.controls_[aria-expanded="true"]]:opacity-100 vjs:has-[+.controls_[aria-expanded="true"]]:delay-0 vjs:has-[+.controls_[aria-expanded="true"]]:duration-75',
|
||||
'vjs:group-hover/root:opacity-100 vjs:group-hover/root:delay-0 vjs:group-hover/root:duration-75',
|
||||
// High contrast mode
|
||||
'contrast-more:from-black/75',
|
||||
'vjs:contrast-more:from-black/75',
|
||||
),
|
||||
Controls: cn(
|
||||
'controls', // FIXME: Temporary className hook for above logic in the overlay. Can be removed once have a proper way to handle controls visibility.
|
||||
'@container/controls absolute inset-x-0 bottom-0 flex items-center gap-3.5 z-20 px-3 pb-3 pt-10 text-white',
|
||||
'vjs:@container/controls vjs:absolute vjs:inset-x-0 vjs:bottom-0 vjs:flex vjs:items-center vjs:gap-3.5 vjs:z-20 vjs:px-3 vjs:pb-3 vjs:pt-10 vjs:text-white',
|
||||
// Animation
|
||||
'transition ease-in-out',
|
||||
'vjs:transition vjs:ease-in-out',
|
||||
// FIXME: Temporary hide/show logic
|
||||
'translate-y-full opacity-0 delay-500 duration-300',
|
||||
'has-[[data-paused]]:translate-y-0 has-[[data-paused]]:opacity-100 has-[[data-paused]]:delay-0 has-[[data-paused]]:duration-75',
|
||||
'has-[[aria-expanded="true"]]:translate-y-0 has-[[aria-expanded="true"]]:opacity-100 has-[[aria-expanded="true"]]:delay-0 has-[[aria-expanded="true"]]:duration-75',
|
||||
'group-hover/root:translate-y-0 group-hover/root:opacity-100 group-hover/root:delay-0 group-hover/root:duration-75',
|
||||
'vjs:translate-y-full vjs:opacity-0 vjs:delay-500 vjs:duration-300',
|
||||
'vjs:has-[[data-paused]]:translate-y-0 vjs:has-[[data-paused]]:opacity-100 vjs:has-[[data-paused]]:delay-0 vjs:has-[[data-paused]]:duration-75',
|
||||
'vjs:has-[[aria-expanded="true"]]:translate-y-0 vjs:has-[[aria-expanded="true"]]:opacity-100 vjs:has-[[aria-expanded="true"]]:delay-0 vjs:has-[[aria-expanded="true"]]:duration-75',
|
||||
'vjs:group-hover/root:translate-y-0 vjs:group-hover/root:opacity-100 vjs:group-hover/root:delay-0 vjs:group-hover/root:duration-75',
|
||||
),
|
||||
Icon: cn('icon'),
|
||||
Button: cn(
|
||||
'group/button cursor-pointer relative shrink-0 transition select-none p-2.5 rounded-md',
|
||||
'vjs:group/button vjs:cursor-pointer vjs:relative vjs:shrink-0 vjs:transition vjs:select-none vjs:p-2.5 vjs:rounded-md',
|
||||
// Background/foreground
|
||||
'bg-transparent text-white',
|
||||
'vjs:bg-transparent vjs:text-white',
|
||||
// Hover and focus states
|
||||
'hover:text-white/80 focus-visible:text-white/80',
|
||||
'vjs:hover:text-white/80 vjs:focus-visible:text-white/80',
|
||||
// Focus state
|
||||
'-outline-offset-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white',
|
||||
'vjs:-outline-offset-2 vjs:focus-visible:outline-2 vjs:focus-visible:outline-offset-2 vjs:focus-visible:outline-white',
|
||||
// Disabled state
|
||||
'aria-disabled:grayscale aria-disabled:opacity-50 aria-disabled:cursor-not-allowed',
|
||||
'vjs:aria-disabled:grayscale vjs:aria-disabled:opacity-50 vjs:aria-disabled:cursor-not-allowed',
|
||||
// Loading state
|
||||
'aria-busy:pointer-events-none aria-busy:cursor-not-allowed',
|
||||
'vjs:aria-busy:pointer-events-none vjs:aria-busy:cursor-not-allowed',
|
||||
// Expanded state
|
||||
'aria-expanded:text-white/80',
|
||||
'vjs:aria-expanded:text-white/80',
|
||||
),
|
||||
ButtonGroup: cn('flex items-center gap-1.5'),
|
||||
ButtonGroup: cn('vjs:flex vjs:items-center vjs:gap-1.5'),
|
||||
IconButton: cn(
|
||||
'grid [&_.icon]:[grid-area:1/1]',
|
||||
'[&_.icon]:shrink-0 [&_.icon]:transition [&_.icon]:duration-300 [&_.icon]:ease-out [&_.icon]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] [&_.icon]:shadow-black/40',
|
||||
'vjs:grid vjs:[&_.icon]:[grid-area:1/1]',
|
||||
'vjs:[&_.icon]:shrink-0 vjs:[&_.icon]:transition vjs:[&_.icon]:duration-300 vjs:[&_.icon]:ease-out vjs:[&_.icon]:drop-shadow-[0_1px_0_var(--tw-shadow-color)] vjs:[&_.icon]:shadow-black/40',
|
||||
),
|
||||
PlayButton: cn(
|
||||
'[&_.pause-icon]:opacity-100 [&[data-paused]_.pause-icon]:opacity-0',
|
||||
'[&_.play-icon]:opacity-0 [&[data-paused]_.play-icon]:opacity-100',
|
||||
'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'),
|
||||
TooltipPopup: cn(
|
||||
'whitespace-nowrap flex origin-[var(--transform-origin)] flex-col rounded-md text-white text-xs @7xl/root:text-sm px-2 py-1',
|
||||
'bg-black/10 backdrop-blur-md',
|
||||
'vjs:whitespace-nowrap vjs:flex vjs:origin-[var(--transform-origin)] vjs:flex-col vjs:rounded-md vjs:text-white vjs:text-xs vjs:@7xl/root:text-sm vjs:px-2 vjs:py-1',
|
||||
'vjs:bg-black/10 vjs:backdrop-blur-md',
|
||||
// Animation
|
||||
'transition-[transform,scale,opacity] data-[ending-style]:scale-90 data-[ending-style]:opacity-0 data-[instant]:duration-0 data-[starting-style]:scale-90 data-[starting-style]:opacity-0',
|
||||
'vjs:transition-[transform,scale,opacity] vjs:data-[ending-style]:scale-90 vjs:data-[ending-style]:opacity-0 vjs:data-[instant]:duration-0 vjs:data-[starting-style]:scale-90 vjs:data-[starting-style]:opacity-0',
|
||||
),
|
||||
PlayTooltipPopup: cn(
|
||||
'[&_.pause-tooltip]:inline [&[data-paused]_.pause-tooltip]:hidden',
|
||||
'[&_.play-tooltip]:hidden [&[data-paused]_.play-tooltip]:inline',
|
||||
'vjs:[&_.pause-tooltip]:inline vjs:[&[data-paused]_.pause-tooltip]:hidden',
|
||||
'vjs:[&_.play-tooltip]:hidden vjs:[&[data-paused]_.play-tooltip]:inline',
|
||||
),
|
||||
PlayTooltip: cn('play-tooltip'),
|
||||
PauseTooltip: cn('pause-tooltip'),
|
||||
MuteButton: cn(
|
||||
'[&_.icon]:hidden',
|
||||
'[&[data-volume-level="high"]_.volume-high-icon]:inline',
|
||||
'[&[data-volume-level="medium"]_.volume-low-icon]:inline',
|
||||
'[&[data-volume-level="low"]_.volume-low-icon]:inline',
|
||||
'[&[data-volume-level="off"]_.volume-off-icon]:inline',
|
||||
'vjs:[&_.icon]:hidden',
|
||||
'vjs:[&[data-volume-level="high"]_.volume-high-icon]:inline',
|
||||
'vjs:[&[data-volume-level="medium"]_.volume-low-icon]:inline',
|
||||
'vjs:[&[data-volume-level="low"]_.volume-low-icon]:inline',
|
||||
'vjs:[&[data-volume-level="off"]_.volume-off-icon]:inline',
|
||||
),
|
||||
VolumeHighIcon: cn('volume-high-icon'),
|
||||
VolumeLowIcon: cn('volume-low-icon'),
|
||||
VolumeOffIcon: cn('volume-off-icon'),
|
||||
FullscreenButton: cn(
|
||||
'[&_.fullscreen-enter-icon]:opacity-100 [&[data-fullscreen]_.fullscreen-enter-icon]:opacity-0',
|
||||
'[&_.fullscreen-exit-icon]:opacity-0 [&[data-fullscreen]_.fullscreen-exit-icon]:opacity-100',
|
||||
'[&_path]:transition-transform ease-out',
|
||||
'vjs:[&_.fullscreen-enter-icon]:opacity-100 vjs:[&[data-fullscreen]_.fullscreen-enter-icon]:opacity-0',
|
||||
'vjs:[&_.fullscreen-exit-icon]:opacity-0 vjs:[&[data-fullscreen]_.fullscreen-exit-icon]:opacity-100',
|
||||
'vjs:[&_path]:transition-transform vjs:ease-out',
|
||||
),
|
||||
FullscreenEnterIcon: cn(
|
||||
'fullscreen-enter-icon',
|
||||
'group-hover/button:[&_.arrow-1]:translate-x-px group-hover/button:[&_.arrow-1]:-translate-y-px',
|
||||
'group-hover/button:[&_.arrow-2]:-translate-x-px group-hover/button:[&_.arrow-2]:translate-y-px',
|
||||
'vjs:group-hover/button:[&_.arrow-1]:translate-x-px vjs:group-hover/button:[&_.arrow-1]:-translate-y-px',
|
||||
'vjs:group-hover/button:[&_.arrow-2]:-translate-x-px vjs:group-hover/button:[&_.arrow-2]:translate-y-px',
|
||||
),
|
||||
FullscreenExitIcon: cn(
|
||||
'fullscreen-exit-icon',
|
||||
'[&_.arrow-1]:translate-x-px [&_.arrow-1]:-translate-y-px',
|
||||
'[&_.arrow-2]:-translate-x-px [&_.arrow-2]:translate-y-px',
|
||||
'group-hover/button:[&_.arrow-1]:translate-0',
|
||||
'group-hover/button:[&_.arrow-2]:translate-0',
|
||||
'vjs:[&_.arrow-1]:translate-x-px vjs:[&_.arrow-1]:-translate-y-px',
|
||||
'vjs:[&_.arrow-2]:-translate-x-px vjs:[&_.arrow-2]:translate-y-px',
|
||||
'vjs:group-hover/button:[&_.arrow-1]:translate-0',
|
||||
'vjs:group-hover/button:[&_.arrow-2]:translate-0',
|
||||
),
|
||||
FullscreenTooltipPopup: cn(
|
||||
'[&_.fullscreen-enter-tooltip]:inline [&[data-fullscreen]_.fullscreen-enter-tooltip]:hidden',
|
||||
'[&_.fullscreen-exit-tooltip]:hidden [&[data-fullscreen]_.fullscreen-exit-tooltip]:inline',
|
||||
'vjs:[&_.fullscreen-enter-tooltip]:inline vjs:[&[data-fullscreen]_.fullscreen-enter-tooltip]:hidden',
|
||||
'vjs:[&_.fullscreen-exit-tooltip]:hidden vjs:[&[data-fullscreen]_.fullscreen-exit-tooltip]:inline',
|
||||
),
|
||||
FullscreenEnterTooltip: cn('fullscreen-enter-tooltip'),
|
||||
FullscreenExitTooltip: cn('fullscreen-exit-tooltip'),
|
||||
TimeSliderRoot: cn('mx-2'),
|
||||
TimeDisplay: cn('tabular-nums text-shadow-2xs/20'),
|
||||
DurationDisplay: cn('text-white/50 contents'),
|
||||
TimeSliderRoot: cn('vjs:mx-2'),
|
||||
TimeDisplay: cn('vjs:tabular-nums vjs:text-shadow-2xs/20'),
|
||||
DurationDisplay: cn('vjs:text-white/50 vjs:contents'),
|
||||
SliderRoot: cn(
|
||||
'flex items-center justify-center flex-1 group/slider relative rounded-sm',
|
||||
'[&[data-orientation="horizontal"]]:h-5 [&[data-orientation="horizontal"]]:min-w-20',
|
||||
'[&[data-orientation="vertical"]]:w-5 [&[data-orientation="vertical"]]:h-18',
|
||||
'vjs:flex vjs:items-center vjs:justify-center vjs:flex-1 vjs:group/slider vjs:relative vjs:rounded-sm',
|
||||
'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
|
||||
'-outline-offset-8 focus-visible:outline-2 focus-visible:outline-offset-8 focus-visible:outline-white',
|
||||
'vjs:-outline-offset-8 vjs:focus-visible:outline-2 vjs:focus-visible:outline-offset-8 vjs:focus-visible:outline-white',
|
||||
),
|
||||
SliderTrack: cn(
|
||||
'relative select-none rounded-full bg-white/10 transition-[height,width] ease-in-out',
|
||||
'[&[data-orientation="horizontal"]]:w-full [&[data-orientation="horizontal"]]:h-[0.1875rem]',
|
||||
'[&[data-orientation="vertical"]]:w-[0.1875rem]',
|
||||
'vjs:relative vjs:select-none vjs:rounded-full vjs:bg-white/10 vjs:transition-[height,width] vjs:ease-in-out',
|
||||
'vjs:[&[data-orientation="horizontal"]]:w-full vjs:[&[data-orientation="horizontal"]]:h-[0.1875rem]',
|
||||
'vjs:[&[data-orientation="vertical"]]:w-[0.1875rem]',
|
||||
),
|
||||
SliderProgress: cn('bg-white rounded-[inherit]'),
|
||||
SliderPointer: cn('hidden'),
|
||||
SliderProgress: cn('vjs:bg-white vjs:rounded-[inherit]'),
|
||||
SliderPointer: cn('vjs:hidden'),
|
||||
SliderThumb: cn(
|
||||
'opacity-0 scale-70 group-hover/slider:opacity-100 group-hover/slider:scale-100 focus-visible:opacity-100 focus-visible:scale-100',
|
||||
'bg-white z-10 size-3 select-none ring ring-black/10 rounded-full shadow-sm shadow-black/15 transition-[opacity,scale] ease-out',
|
||||
'-outline-offset-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-amber-500',
|
||||
'[&[data-orientation="horizontal"]]:hover:cursor-ew-resize',
|
||||
'[&[data-orientation="vertical"]]:hover:cursor-ns-resize',
|
||||
'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',
|
||||
),
|
||||
PopoverPopup: cn(
|
||||
'py-2',
|
||||
'vjs:py-2',
|
||||
// Animation
|
||||
'transition-[transform,scale,opacity] data-[ending-style]:scale-90 data-[ending-style]:opacity-0 data-[instant]:duration-0 data-[starting-style]:scale-90 data-[starting-style]:opacity-0',
|
||||
'vjs:transition-[transform,scale,opacity] vjs:data-[ending-style]:scale-90 vjs:data-[ending-style]:opacity-0 vjs:data-[instant]:duration-0 vjs:data-[starting-style]:scale-90 vjs:data-[starting-style]:opacity-0',
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
@import 'tailwindcss/preflight.css' layer(base) prefix(vjs);
|
||||
@@ -1,4 +1,5 @@
|
||||
import { defineConfig } from 'tsdown';
|
||||
import buildStyles from './build/build-styles.ts';
|
||||
|
||||
export default defineConfig({
|
||||
entry: 'src/index.ts',
|
||||
@@ -12,4 +13,9 @@ export default defineConfig({
|
||||
dts: {
|
||||
oxc: true,
|
||||
},
|
||||
hooks: {
|
||||
'build:done': async () => {
|
||||
await buildStyles();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Generated
+28
-39
@@ -292,12 +292,24 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../react-media-store
|
||||
devDependencies:
|
||||
'@tailwindcss/cli':
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.14
|
||||
'@types/react':
|
||||
specifier: ^18.0.0
|
||||
version: 18.3.24
|
||||
postcss:
|
||||
specifier: ^8.4.49
|
||||
version: 8.5.6
|
||||
postcss-prefix-selector:
|
||||
specifier: ^1.16.1
|
||||
version: 1.16.1(postcss@8.5.6)
|
||||
react:
|
||||
specifier: ^18.0.0
|
||||
version: 18.3.1
|
||||
tailwindcss:
|
||||
specifier: ^4.1.13
|
||||
version: 4.1.14
|
||||
tsdown:
|
||||
specifier: ^0.15.9
|
||||
version: 0.15.9(typescript@5.9.2)
|
||||
@@ -458,9 +470,6 @@ importers:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
devDependencies:
|
||||
'@tailwindcss/cli':
|
||||
specifier: ^4.1.14
|
||||
version: 4.1.14
|
||||
'@testing-library/jest-dom':
|
||||
specifier: ^6.9.1
|
||||
version: 6.9.1
|
||||
@@ -491,18 +500,9 @@ importers:
|
||||
jsdom:
|
||||
specifier: ^27.0.0
|
||||
version: 27.0.0(postcss@8.5.6)
|
||||
postcss:
|
||||
specifier: ^8.4.49
|
||||
version: 8.5.6
|
||||
postcss-nested:
|
||||
specifier: ^7.0.2
|
||||
version: 7.0.2(postcss@8.5.6)
|
||||
postcss-prefix-selector:
|
||||
specifier: ^1.16.1
|
||||
version: 1.16.1(postcss@8.5.6)
|
||||
vitest:
|
||||
specifier: ^3.2.4
|
||||
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.6)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.0.0)(lightningcss@1.30.1)(yaml@2.8.1)
|
||||
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.6)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(yaml@2.8.1)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -4395,12 +4395,6 @@ packages:
|
||||
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
postcss-nested@7.0.2:
|
||||
resolution: {integrity: sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==}
|
||||
engines: {node: '>=18.0'}
|
||||
peerDependencies:
|
||||
postcss: ^8.2.14
|
||||
|
||||
postcss-prefix-selector@1.16.1:
|
||||
resolution: {integrity: sha512-Umxu+FvKMwlY6TyDzGFoSUnzW+NOfMBLyC1tAkIjgX+Z/qGspJeRjVC903D7mx7TuBpJlwti2ibXtWuA7fKMeQ==}
|
||||
peerDependencies:
|
||||
@@ -6456,7 +6450,7 @@ snapshots:
|
||||
https-proxy-agent: 7.0.6
|
||||
node-fetch: 2.7.0
|
||||
nopt: 8.1.0
|
||||
semver: 7.7.3
|
||||
semver: 7.7.2
|
||||
tar: 7.5.1
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
@@ -7159,7 +7153,7 @@ snapshots:
|
||||
fast-glob: 3.3.3
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.5
|
||||
semver: 7.7.3
|
||||
semver: 7.7.2
|
||||
ts-api-utils: 2.1.0(typescript@5.9.2)
|
||||
typescript: 5.9.2
|
||||
transitivePeerDependencies:
|
||||
@@ -7261,7 +7255,7 @@ snapshots:
|
||||
std-env: 3.9.0
|
||||
test-exclude: 7.0.1
|
||||
tinyrainbow: 2.0.0
|
||||
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.6)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.0.0)(lightningcss@1.30.1)(yaml@2.8.1)
|
||||
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.6)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -7272,7 +7266,7 @@ snapshots:
|
||||
eslint: 9.37.0(jiti@2.6.1)
|
||||
optionalDependencies:
|
||||
typescript: 5.9.2
|
||||
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.6)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.0.0)(lightningcss@1.30.1)(yaml@2.8.1)
|
||||
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.6)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -7321,7 +7315,7 @@ snapshots:
|
||||
sirv: 3.0.2
|
||||
tinyglobby: 0.2.15
|
||||
tinyrainbow: 2.0.0
|
||||
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.6)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.0.0)(lightningcss@1.30.1)(yaml@2.8.1)
|
||||
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.6)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(yaml@2.8.1)
|
||||
|
||||
'@vitest/utils@3.2.4':
|
||||
dependencies:
|
||||
@@ -7497,7 +7491,7 @@ snapshots:
|
||||
espree: 10.4.0
|
||||
fast-glob: 3.3.3
|
||||
is-glob: 4.0.3
|
||||
semver: 7.7.3
|
||||
semver: 7.7.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -8166,7 +8160,7 @@ snapshots:
|
||||
eslint-compat-utils@0.6.5(eslint@9.37.0(jiti@2.6.1)):
|
||||
dependencies:
|
||||
eslint: 9.37.0(jiti@2.6.1)
|
||||
semver: 7.7.3
|
||||
semver: 7.7.2
|
||||
|
||||
eslint-config-flat-gitignore@2.1.0(eslint@9.37.0(jiti@2.6.1)):
|
||||
dependencies:
|
||||
@@ -8255,7 +8249,7 @@ snapshots:
|
||||
esquery: 1.6.0
|
||||
object-deep-merge: 1.0.5
|
||||
parse-imports-exports: 0.2.4
|
||||
semver: 7.7.3
|
||||
semver: 7.7.2
|
||||
spdx-expression-parse: 4.0.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -8303,7 +8297,7 @@ snapshots:
|
||||
globals: 15.15.0
|
||||
globrex: 0.1.2
|
||||
ignore: 5.3.2
|
||||
semver: 7.7.3
|
||||
semver: 7.7.2
|
||||
ts-declaration-location: 1.0.7(typescript@5.9.2)
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
@@ -8506,7 +8500,7 @@ snapshots:
|
||||
pluralize: 8.0.0
|
||||
regexp-tree: 0.1.27
|
||||
regjsparser: 0.12.0
|
||||
semver: 7.7.3
|
||||
semver: 7.7.2
|
||||
strip-indent: 4.1.0
|
||||
|
||||
eslint-plugin-unused-imports@4.2.0(@typescript-eslint/eslint-plugin@8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.37.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.37.0(jiti@2.6.1)):
|
||||
@@ -8522,7 +8516,7 @@ snapshots:
|
||||
natural-compare: 1.4.0
|
||||
nth-check: 2.1.1
|
||||
postcss-selector-parser: 6.1.2
|
||||
semver: 7.7.3
|
||||
semver: 7.7.2
|
||||
vue-eslint-parser: 10.2.0(eslint@9.37.0(jiti@2.6.1))
|
||||
xml-name-validator: 4.0.0
|
||||
optionalDependencies:
|
||||
@@ -9325,7 +9319,7 @@ snapshots:
|
||||
acorn: 8.15.0
|
||||
eslint-visitor-keys: 3.4.3
|
||||
espree: 9.6.1
|
||||
semver: 7.7.3
|
||||
semver: 7.7.2
|
||||
|
||||
jsx-ast-utils@3.3.5:
|
||||
dependencies:
|
||||
@@ -9483,7 +9477,7 @@ snapshots:
|
||||
|
||||
make-dir@4.0.0:
|
||||
dependencies:
|
||||
semver: 7.7.3
|
||||
semver: 7.7.2
|
||||
|
||||
markdown-extensions@2.0.0: {}
|
||||
|
||||
@@ -10219,11 +10213,6 @@ snapshots:
|
||||
|
||||
possible-typed-array-names@1.1.0: {}
|
||||
|
||||
postcss-nested@7.0.2(postcss@8.5.6):
|
||||
dependencies:
|
||||
postcss: 8.5.6
|
||||
postcss-selector-parser: 7.1.0
|
||||
|
||||
postcss-prefix-selector@1.16.1(postcss@8.5.6):
|
||||
dependencies:
|
||||
postcss: 8.5.6
|
||||
@@ -11305,7 +11294,7 @@ snapshots:
|
||||
optionalDependencies:
|
||||
vite: 6.3.6(@types/node@22.18.6)(jiti@2.6.1)(lightningcss@1.30.1)(yaml@2.8.1)
|
||||
|
||||
vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.6)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.0.0)(lightningcss@1.30.1)(yaml@2.8.1):
|
||||
vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.6)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.1)(yaml@2.8.1):
|
||||
dependencies:
|
||||
'@types/chai': 5.2.2
|
||||
'@vitest/expect': 3.2.4
|
||||
@@ -11357,7 +11346,7 @@ snapshots:
|
||||
eslint-visitor-keys: 4.2.1
|
||||
espree: 10.4.0
|
||||
esquery: 1.6.0
|
||||
semver: 7.7.3
|
||||
semver: 7.7.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"compile-vjs-styles": "node scripts/compile-vjs-styles.js",
|
||||
"dev": "npm run compile-vjs-styles && astro dev",
|
||||
"build": "npm run compile-vjs-styles && astro build",
|
||||
"dev": " astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro",
|
||||
"test": "vitest run",
|
||||
@@ -43,7 +42,6 @@
|
||||
"unist-util-visit": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/cli": "^4.1.14",
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
@@ -54,9 +52,6 @@
|
||||
"@vitest/ui": "^3.2.4",
|
||||
"babel-plugin-react-compiler": "1.0.0",
|
||||
"jsdom": "^27.0.0",
|
||||
"postcss": "^8.4.49",
|
||||
"postcss-nested": "^7.0.2",
|
||||
"postcss-prefix-selector": "^1.16.1",
|
||||
"vitest": "^3.2.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { execSync } from 'node:child_process';
|
||||
import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import process from 'node:process';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import postcss from 'postcss';
|
||||
import nested from 'postcss-nested';
|
||||
import prefixSelector from 'postcss-prefix-selector';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const rootDir = join(__dirname, '..');
|
||||
|
||||
const inputFile = 'src/styles/vjs-input.css';
|
||||
const tempFile = 'src/styles/vjs-temp.css';
|
||||
const outputFile = 'src/styles/vjs.css';
|
||||
|
||||
console.log('🎨 Compiling VJS styles...');
|
||||
|
||||
try {
|
||||
// Step 1: Run Tailwind CLI
|
||||
console.log(' → Running Tailwind CSS compiler...');
|
||||
execSync(
|
||||
`npx @tailwindcss/cli -i ${inputFile} -o ${tempFile}`,
|
||||
{ cwd: rootDir, stdio: 'inherit' },
|
||||
);
|
||||
|
||||
// Step 2: Read compiled CSS
|
||||
const tempPath = join(rootDir, tempFile);
|
||||
const css = readFileSync(tempPath, 'utf-8');
|
||||
|
||||
// Step 3: Post-process with PostCSS to scope selectors
|
||||
console.log(' → Scoping selectors to .vjs...');
|
||||
const result = await postcss([
|
||||
nested(),
|
||||
prefixSelector({
|
||||
prefix: '.vjs',
|
||||
transform(prefix, selector, prefixedSelector) {
|
||||
// this is supposed to happen automatically, but isn't... idk
|
||||
if (selector === 'body' || selector === 'html' || selector === ':root') {
|
||||
return prefix;
|
||||
} else if (selector === ':host') {
|
||||
return selector;
|
||||
} else {
|
||||
return prefixedSelector;
|
||||
}
|
||||
},
|
||||
}),
|
||||
]).process(css, { from: tempFile, to: outputFile });
|
||||
|
||||
// Step 3.5: For reasons I don't fully understand, we're getting duplicate .vjs classes
|
||||
// e.g., .vjs .vjs or .vjs .vjs .vjs
|
||||
// let's just regex them to oblivion
|
||||
result.css = result.css.replace(/(\.vjs\s+)+/g, '.vjs ');
|
||||
|
||||
// Step 4: Write output
|
||||
const outputPath = join(rootDir, outputFile);
|
||||
writeFileSync(outputPath, result.css, 'utf-8');
|
||||
|
||||
// Step 5: Clean up temp file
|
||||
if (existsSync(tempPath)) {
|
||||
unlinkSync(tempPath);
|
||||
}
|
||||
|
||||
console.log(`✅ VJS styles compiled to ${outputFile}`);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to compile VJS styles:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -2,7 +2,8 @@ import { useStore } from '@nanostores/react';
|
||||
import { FrostedSkin, MediaProvider, MinimalSkin, Video } from '@vjs-10/react';
|
||||
import { skin } from '@/stores/homePageDemos';
|
||||
import { PLAYBACK_ID } from './config';
|
||||
import '@/styles/vjs.css';
|
||||
import '@vjs-10/react/skins/frosted.css';
|
||||
import '@vjs-10/react/skins/minimal.css';
|
||||
|
||||
export default function HeroVideo({ className, poster }: { className?: string; poster: string }) {
|
||||
// Subscribe to skin store for future skin switching functionality
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
@import 'tailwindcss';
|
||||
|
||||
@source "../../../packages/react";
|
||||
|
||||
/* theme inline tells tailwind to reference the value of these properties */
|
||||
@theme inline {
|
||||
--font-*: initial;
|
||||
/* --font-instrument-sans and --font-ibm-plex-mono are defined in Base.astro */
|
||||
--font-sans: var(--font-instrument-sans);
|
||||
--font-mono: var(--font-ibm-plex-mono);
|
||||
}
|
||||
Reference in New Issue
Block a user