mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(skin): add error dialogs (#603)
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@videojs/core": "workspace:*",
|
||||
"@videojs/html": "workspace:*",
|
||||
"@videojs/icons": "workspace:*",
|
||||
"@videojs/react": "workspace:*",
|
||||
"@videojs/store": "workspace:*",
|
||||
"@videojs/utils": "workspace:*"
|
||||
@@ -18,9 +19,9 @@
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@vitejs/plugin-react": "^4.0.0",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"@tailwindcss/vite": "^4.2.0",
|
||||
"@vitejs/plugin-react": "^5.1.4",
|
||||
"tailwindcss": "^4.2.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"tsx": "^4.0.0",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Sandbox</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
<link rel="stylesheet" href="../styles.css" />
|
||||
</head>
|
||||
<body class="p-8 font-mono text-neutral-900">
|
||||
<h1 class="text-2xl font-bold mb-6">Sandbox</h1>
|
||||
@@ -12,6 +12,7 @@
|
||||
<li><a href="/core/" class="text-blue-600 underline hover:text-blue-800">Core</a></li>
|
||||
<li><a href="/html/" class="text-blue-600 underline hover:text-blue-800">HTML</a></li>
|
||||
<li><a href="/react/" class="text-blue-600 underline hover:text-blue-800">React</a></li>
|
||||
<li><a href="/react-tailwind/" class="text-blue-600 underline hover:text-blue-800">React & Tailwind</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const SKINS = ['default', 'minimal'] as const;
|
||||
@@ -1,7 +1,7 @@
|
||||
// HTML sandbox — Web player (DOM/Browser)
|
||||
// http://localhost:5173/html/
|
||||
|
||||
import { createPlayer, features, MediaElement } from '@videojs/html';
|
||||
import { createPlayer, features } from '@videojs/html';
|
||||
|
||||
const { PlayerElement } = createPlayer({
|
||||
features: features.video,
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Sandbox</title>
|
||||
<link rel="stylesheet" href="../styles.css" />
|
||||
</head>
|
||||
<body class="p-8 font-mono text-neutral-900">
|
||||
<h1 class="text-2xl font-bold mb-6">Sandbox</h1>
|
||||
<ul class="flex gap-4">
|
||||
<li><a href="/core/" class="text-blue-600 underline hover:text-blue-800">Core</a></li>
|
||||
<li><a href="/html/" class="text-blue-600 underline hover:text-blue-800">HTML</a></li>
|
||||
<li><a href="/react/" class="text-blue-600 underline hover:text-blue-800">React</a></li>
|
||||
<li><a href="/react-tailwind/" class="text-blue-600 underline hover:text-blue-800">React & Tailwind</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Sandbox — React & Tailwind</title>
|
||||
<link rel="stylesheet" href="../styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,46 @@
|
||||
// React & Tailwind Sandbox
|
||||
// http://localhost:5173/react-tailwind/
|
||||
|
||||
import { createPlayer, features } from '@videojs/react';
|
||||
import { MinimalVideoSkinTailwind, Video, type VideoSkinProps, VideoSkinTailwind } from '@videojs/react/video';
|
||||
import { useState } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { SKINS } from '../constants';
|
||||
import type { Skin } from '../types';
|
||||
|
||||
const { Provider } = createPlayer({
|
||||
features: features.video,
|
||||
});
|
||||
|
||||
function SkinComponent({ skin, ...props }: { skin: Skin } & VideoSkinProps) {
|
||||
switch (skin) {
|
||||
case 'default':
|
||||
return <VideoSkinTailwind {...props} />;
|
||||
case 'minimal':
|
||||
return <MinimalVideoSkinTailwind {...props} />;
|
||||
}
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [skin, setSkin] = useState<Skin>('default');
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center items-center gap-4 my-4">
|
||||
<select value={skin} onChange={(e) => setSkin(e.target.value as Skin)} aria-label="Skin">
|
||||
{SKINS.map((s) => (
|
||||
<option key={s} value={s}>
|
||||
{s}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<Provider>
|
||||
<SkinComponent skin={skin} className="w-full aspect-video max-w-4xl mx-auto">
|
||||
<Video src="https://stream.mux.com/lhnU49l1VGi3zrTAZhDm9LUUxSjpaPW9BL4jY25Kwo4/highest.mp4" />
|
||||
</SkinComponent>
|
||||
</Provider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
createRoot(document.getElementById('root')!).render(<App />);
|
||||
@@ -1,21 +1,37 @@
|
||||
// React sandbox — React player
|
||||
// http://localhost:5173/react/
|
||||
|
||||
import { Container, createPlayer, features } from '@videojs/react';
|
||||
import { createPlayer, features } from '@videojs/react';
|
||||
import { Video } from '@videojs/react/video';
|
||||
import { useState } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { SKINS } from '../constants';
|
||||
import type { Skin } from '../types';
|
||||
import { SkinComponent } from './skins';
|
||||
|
||||
const { Provider } = createPlayer({
|
||||
features: features.video,
|
||||
});
|
||||
|
||||
function App() {
|
||||
const [skin, setSkin] = useState<Skin>('default');
|
||||
|
||||
return (
|
||||
<Provider>
|
||||
<Container>
|
||||
<Video src="https://stream.mux.com/lhnU49l1VGi3zrTAZhDm9LUUxSjpaPW9BL4jY25Kwo4/highest.mp4" />
|
||||
</Container>
|
||||
</Provider>
|
||||
<div className="flex flex-col justify-center items-center gap-4 my-4">
|
||||
<select value={skin} onChange={(e) => setSkin(e.target.value as Skin)} aria-label="Skin">
|
||||
{SKINS.map((s) => (
|
||||
<option key={s} value={s}>
|
||||
{s}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<Provider>
|
||||
<SkinComponent skin={skin} className="w-full aspect-video max-w-4xl mx-auto">
|
||||
<Video src="https://stream.mux.com/lhnU49l1VGi3zrTAZhDm9LUUxSjpaPW9BL4jY25Kwo4/highest.mp4" />
|
||||
</SkinComponent>
|
||||
</Provider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { VideoSkinProps } from '@videojs/react/video';
|
||||
import { MinimalVideoSkin, VideoSkin } from '@videojs/react/video';
|
||||
import minimalSkinUrl from '@videojs/react/video/minimal-skin.css?url';
|
||||
import defaultSkinUrl from '@videojs/react/video/skin.css?url';
|
||||
import { useEffect } from 'react';
|
||||
import type { Skin } from '../types';
|
||||
|
||||
const stylesheets: Record<Skin, string> = {
|
||||
default: defaultSkinUrl,
|
||||
minimal: minimalSkinUrl,
|
||||
};
|
||||
|
||||
function useStylesheet(url: string) {
|
||||
useEffect(() => {
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = url;
|
||||
document.head.appendChild(link);
|
||||
return () => {
|
||||
link.remove();
|
||||
};
|
||||
}, [url]);
|
||||
}
|
||||
|
||||
export function SkinComponent({ skin, ...props }: { skin: Skin } & VideoSkinProps) {
|
||||
useStylesheet(stylesheets[skin]);
|
||||
|
||||
switch (skin) {
|
||||
case 'default':
|
||||
return <VideoSkin {...props} />;
|
||||
case 'minimal':
|
||||
return <MinimalVideoSkin {...props} />;
|
||||
}
|
||||
}
|
||||
@@ -1 +1,3 @@
|
||||
@import "tailwindcss";
|
||||
@source "../templates";
|
||||
@source "../node_modules/@videojs/react";
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import type { SKINS } from './constants';
|
||||
|
||||
export type Skin = (typeof SKINS)[number];
|
||||
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -10,7 +10,7 @@ export default defineConfig({
|
||||
dedupe: ['react', 'react-dom'],
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: ['@videojs/core', '@videojs/html', '@videojs/react', '@videojs/store', '@videojs/utils'],
|
||||
exclude: ['@videojs/core', '@videojs/html', '@videojs/icons', '@videojs/react', '@videojs/store', '@videojs/utils'],
|
||||
},
|
||||
build: {
|
||||
outDir: resolve(__dirname, 'dist'),
|
||||
@@ -21,6 +21,7 @@ export default defineConfig({
|
||||
core: resolve(__dirname, 'src/core/index.html'),
|
||||
html: resolve(__dirname, 'src/html/index.html'),
|
||||
react: resolve(__dirname, 'src/react/index.html'),
|
||||
'react-tailwind': resolve(__dirname, 'src/react-tailwind/index.html'),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user