mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
fix(site): reset installation guide to implemented features (#707)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
4b282ff074
commit
2db6be75be
@@ -9,22 +9,25 @@ function getSkinImportParts(skin: Skin): { group: string; skinFile: string } {
|
||||
return { group: skin, skinFile: 'skin' };
|
||||
}
|
||||
|
||||
// jsdelivr doesn't resolve Node package exports, so we use the full file path
|
||||
const CDN_BASE = 'https://cdn.jsdelivr.net/npm/@videojs/html@next/dist/default/define';
|
||||
|
||||
function generateCdnCode(useCase: UseCase, skin: Skin): string {
|
||||
if (useCase === 'background-video') {
|
||||
return `<script>
|
||||
import 'https://cdn.jsdelivr.net/npm/videojs/html/background/player.js';
|
||||
import 'https://cdn.jsdelivr.net/npm/videojs/html/background/skin.js';
|
||||
import '${CDN_BASE}/background/player.js';
|
||||
import '${CDN_BASE}/background/skin.js';
|
||||
</script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/videojs/html/background/skin.css" />`;
|
||||
<link rel="stylesheet" href="${CDN_BASE}/background/skin.css" />`;
|
||||
}
|
||||
|
||||
const { group, skinFile } = getSkinImportParts(skin);
|
||||
|
||||
return `<script>
|
||||
import 'https://cdn.jsdelivr.net/npm/videojs/html/${group}/player.js';
|
||||
import 'https://cdn.jsdelivr.net/npm/videojs/html/${group}/${skinFile}.js';
|
||||
import '${CDN_BASE}/${group}/player.js';
|
||||
import '${CDN_BASE}/${group}/${skinFile}.js';
|
||||
</script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/videojs/html/${group}/${skinFile}.css" />`;
|
||||
<link rel="stylesheet" href="${CDN_BASE}/${group}/${skinFile}.css" />`;
|
||||
}
|
||||
|
||||
export default function HTMLCdnCodeBlock() {
|
||||
|
||||
@@ -48,16 +48,16 @@ export default function HTMLInstallTabs() {
|
||||
<HTMLCdnCodeBlock />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="npm">
|
||||
<ClientCode code="npm install @videojs/html" lang="bash" />
|
||||
<ClientCode code="npm install @videojs/html@next" lang="bash" />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="pnpm">
|
||||
<ClientCode code="pnpm add @videojs/html" lang="bash" />
|
||||
<ClientCode code="pnpm add @videojs/html@next" lang="bash" />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="yarn">
|
||||
<ClientCode code="yarn add @videojs/html" lang="bash" />
|
||||
<ClientCode code="yarn add @videojs/html@next" lang="bash" />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="bun">
|
||||
<ClientCode code="bun add @videojs/html" lang="bash" />
|
||||
<ClientCode code="bun add @videojs/html@next" lang="bash" />
|
||||
</TabsPanel>
|
||||
</TabsRoot>
|
||||
</div>
|
||||
|
||||
@@ -2,25 +2,25 @@ import { useStore } from '@nanostores/react';
|
||||
import ClientCode from '@/components/Code/ClientCode';
|
||||
import { Tab, TabsList, TabsPanel, TabsRoot } from '@/components/Tabs';
|
||||
import type { Renderer, Skin, UseCase } from '@/stores/installation';
|
||||
import { installMethod, muxPlaybackId, renderer, skin, sourceUrl, useCase } from '@/stores/installation';
|
||||
import { installMethod, renderer, skin, sourceUrl, useCase } from '@/stores/installation';
|
||||
|
||||
function getRendererTag(renderer: Renderer): string {
|
||||
const map: Record<Renderer, string> = {
|
||||
'background-video': 'background-video',
|
||||
cloudflare: 'cloudflare-video',
|
||||
dash: 'dash-video',
|
||||
// cloudflare: 'cloudflare-video',
|
||||
// dash: 'dash-video',
|
||||
hls: 'hls-video',
|
||||
'html5-audio': 'audio',
|
||||
'html5-video': 'video',
|
||||
jwplayer: 'jwplayer-video',
|
||||
'mux-audio': 'mux-audio',
|
||||
'mux-background-video': 'mux-background-video',
|
||||
'mux-video': 'mux-video',
|
||||
// jwplayer: 'jwplayer-video',
|
||||
// 'mux-audio': 'mux-audio',
|
||||
// 'mux-background-video': 'mux-background-video',
|
||||
// 'mux-video': 'mux-video',
|
||||
// shaka: 'shaka-video',
|
||||
spotify: 'spotify-audio',
|
||||
vimeo: 'vimeo-video',
|
||||
wistia: 'wistia-video',
|
||||
youtube: 'youtube-video',
|
||||
// spotify: 'spotify-audio',
|
||||
// vimeo: 'vimeo-video',
|
||||
// wistia: 'wistia-video',
|
||||
// youtube: 'youtube-video',
|
||||
};
|
||||
return map[renderer];
|
||||
}
|
||||
@@ -42,34 +42,22 @@ function getSkinTag(useCase: UseCase, skin: Skin): string {
|
||||
const map: Record<Skin, string> = {
|
||||
video: 'video-skin',
|
||||
audio: 'audio-skin',
|
||||
'minimal-video': 'minimal-video-skin',
|
||||
'minimal-audio': 'minimal-audio-skin',
|
||||
'minimal-video': 'video-minimal-skin',
|
||||
'minimal-audio': 'audio-minimal-skin',
|
||||
};
|
||||
return map[skin];
|
||||
}
|
||||
|
||||
function getRendererElement(renderer: Renderer, playbackId: string | null, url: string): string {
|
||||
function getRendererElement(renderer: Renderer, url: string): string {
|
||||
const tag = getRendererTag(renderer);
|
||||
|
||||
// When renderer is a mux variant and we have a playback ID, use playback-id attribute
|
||||
if ((renderer === 'mux-video' || renderer === 'mux-audio' || renderer === 'mux-background-video') && playbackId) {
|
||||
return `<${tag} playback-id="${playbackId}"></${tag}>`;
|
||||
}
|
||||
|
||||
const src = url.trim() || '...';
|
||||
return `<${tag} src="${src}"></${tag}>`;
|
||||
}
|
||||
|
||||
function generateHTMLCode(
|
||||
useCase: UseCase,
|
||||
skin: Skin,
|
||||
renderer: Renderer,
|
||||
playbackId: string | null,
|
||||
url: string
|
||||
): string {
|
||||
function generateHTMLCode(useCase: UseCase, skin: Skin, renderer: Renderer, url: string): string {
|
||||
const providerTag = getProviderTag(useCase);
|
||||
const skinTag = getSkinTag(useCase, skin);
|
||||
const rendererElement = getRendererElement(renderer, playbackId, url);
|
||||
const rendererElement = getRendererElement(renderer, url);
|
||||
|
||||
return `<!--
|
||||
The PlayerProvider passes state between the UI components
|
||||
@@ -99,24 +87,37 @@ function getSkinImportParts(skin: Skin): { group: string; skinFile: string } {
|
||||
return { group: skin, skinFile: 'skin' };
|
||||
}
|
||||
|
||||
function generateJS(useCase: UseCase, skin: Skin): string {
|
||||
function getMediaImportSubpath(renderer: Renderer): string | null {
|
||||
const map: Partial<Record<Renderer, string>> = {
|
||||
hls: 'hls-video',
|
||||
// 'mux-audio': 'mux-audio',
|
||||
// 'mux-background-video': 'mux-background-video',
|
||||
// 'mux-video': 'mux-video',
|
||||
};
|
||||
return map[renderer] ?? null;
|
||||
}
|
||||
|
||||
function generateJS(useCase: UseCase, skin: Skin, renderer: Renderer): string {
|
||||
if (useCase === 'background-video') {
|
||||
const mediaSubpath = getMediaImportSubpath(renderer);
|
||||
const mediaImport = mediaSubpath ? `\nimport '@videojs/html/media/${mediaSubpath}';` : '';
|
||||
return `import '@videojs/html/background/player';
|
||||
import '@videojs/html/background/skin';
|
||||
import '@videojs/html/background/skin.css';
|
||||
import '@videojs/html/background/video';`;
|
||||
import '@videojs/html/background/video';${mediaImport}`;
|
||||
}
|
||||
const { group, skinFile } = getSkinImportParts(skin);
|
||||
const mediaSubpath = getMediaImportSubpath(renderer);
|
||||
const mediaImport = mediaSubpath ? `\nimport '@videojs/html/media/${mediaSubpath}';` : '';
|
||||
return `import '@videojs/html/${group}/player';
|
||||
import '@videojs/html/${group}/${skinFile}';
|
||||
import '@videojs/html/${group}/${skinFile}.css';`;
|
||||
import '@videojs/html/${group}/${skinFile}.css';${mediaImport}`;
|
||||
}
|
||||
|
||||
export default function HTMLUsageCodeBlock() {
|
||||
const $useCase = useStore(useCase);
|
||||
const $skin = useStore(skin);
|
||||
const $renderer = useStore(renderer);
|
||||
const $muxPlaybackId = useStore(muxPlaybackId);
|
||||
const $installMethod = useStore(installMethod);
|
||||
const $sourceUrl = useStore(sourceUrl);
|
||||
|
||||
@@ -130,7 +131,7 @@ export default function HTMLUsageCodeBlock() {
|
||||
</Tab>
|
||||
</TabsList>
|
||||
<TabsPanel value="javascript" initial>
|
||||
<ClientCode code={generateJS($useCase, $skin)} lang="javascript" />
|
||||
<ClientCode code={generateJS($useCase, $skin, $renderer)} lang="javascript" />
|
||||
</TabsPanel>
|
||||
</TabsRoot>
|
||||
)}
|
||||
@@ -141,7 +142,7 @@ export default function HTMLUsageCodeBlock() {
|
||||
</Tab>
|
||||
</TabsList>
|
||||
<TabsPanel value="html" initial>
|
||||
<ClientCode code={generateHTMLCode($useCase, $skin, $renderer, $muxPlaybackId, $sourceUrl)} lang="html" />
|
||||
<ClientCode code={generateHTMLCode($useCase, $skin, $renderer, $sourceUrl)} lang="html" />
|
||||
</TabsPanel>
|
||||
</TabsRoot>
|
||||
</>
|
||||
|
||||
@@ -2,25 +2,25 @@ import { useStore } from '@nanostores/react';
|
||||
import ClientCode from '@/components/Code/ClientCode';
|
||||
import { Tab, TabsList, TabsPanel, TabsRoot } from '@/components/Tabs';
|
||||
import type { Renderer, Skin, UseCase } from '@/stores/installation';
|
||||
import { muxPlaybackId, renderer, skin, useCase } from '@/stores/installation';
|
||||
import { renderer, skin, useCase } from '@/stores/installation';
|
||||
|
||||
function getRendererComponent(renderer: Renderer): string {
|
||||
const map: Record<Renderer, string> = {
|
||||
'background-video': 'BackgroundVideo',
|
||||
cloudflare: 'CloudflareVideo',
|
||||
dash: 'DashVideo',
|
||||
// cloudflare: 'CloudflareVideo',
|
||||
// dash: 'DashVideo',
|
||||
hls: 'HlsVideo',
|
||||
'html5-audio': 'Audio',
|
||||
'html5-video': 'Video',
|
||||
jwplayer: 'JwplayerVideo',
|
||||
'mux-audio': 'MuxAudio',
|
||||
'mux-background-video': 'MuxBackgroundVideo',
|
||||
'mux-video': 'MuxVideo',
|
||||
// shaka: 'ShakaVideo', this one probably adds more confusion than help at this level
|
||||
spotify: 'SpotifyAudio',
|
||||
vimeo: 'VimeoVideo',
|
||||
wistia: 'WistiaVideo',
|
||||
youtube: 'YoutubeVideo',
|
||||
// jwplayer: 'JwplayerVideo',
|
||||
// mux-audio: 'MuxAudio',
|
||||
// mux-background-video: 'MuxBackgroundVideo',
|
||||
// mux-video: 'MuxVideo',
|
||||
// shaka: 'ShakaVideo',
|
||||
// spotify: 'SpotifyAudio',
|
||||
// vimeo: 'VimeoVideo',
|
||||
// wistia: 'WistiaVideo',
|
||||
// youtube: 'YoutubeVideo',
|
||||
};
|
||||
return map[renderer];
|
||||
}
|
||||
@@ -43,9 +43,9 @@ function getSkinImportParts(skin: Skin): { group: string; skinFile: string } {
|
||||
|
||||
function getUseCaseFeatures(useCase: UseCase): string {
|
||||
const map: Record<UseCase, string> = {
|
||||
'default-video': 'video',
|
||||
'default-audio': 'audio',
|
||||
'background-video': 'background',
|
||||
'default-video': 'videoFeatures',
|
||||
'default-audio': 'audioFeatures',
|
||||
'background-video': 'backgroundFeatures',
|
||||
};
|
||||
return map[useCase];
|
||||
}
|
||||
@@ -56,22 +56,22 @@ function isPresetRenderer(renderer: Renderer): boolean {
|
||||
|
||||
function getRendererMediaSubpath(renderer: Renderer): string {
|
||||
const map: Partial<Record<Renderer, string>> = {
|
||||
cloudflare: 'cloudflare-video',
|
||||
dash: 'dash-video',
|
||||
// cloudflare: 'cloudflare-video',
|
||||
// dash: 'dash-video',
|
||||
hls: 'hls-video',
|
||||
jwplayer: 'jwplayer-video',
|
||||
'mux-audio': 'mux-audio',
|
||||
'mux-background-video': 'mux-background-video',
|
||||
'mux-video': 'mux-video',
|
||||
spotify: 'spotify-audio',
|
||||
vimeo: 'vimeo-video',
|
||||
wistia: 'wistia-video',
|
||||
youtube: 'youtube-video',
|
||||
// jwplayer: 'jwplayer-video',
|
||||
// 'mux-audio': 'mux-audio',
|
||||
// 'mux-background-video': 'mux-background-video',
|
||||
// 'mux-video': 'mux-video',
|
||||
// spotify: 'spotify-audio',
|
||||
// vimeo: 'vimeo-video',
|
||||
// wistia: 'wistia-video',
|
||||
// youtube: 'youtube-video',
|
||||
};
|
||||
return map[renderer] ?? renderer;
|
||||
}
|
||||
|
||||
function generateReactCode(useCase: UseCase, skin: Skin, renderer: Renderer, playbackId: string | null): string {
|
||||
function generateReactCode(useCase: UseCase, skin: Skin, renderer: Renderer): string {
|
||||
const rendererComponent = getRendererComponent(renderer);
|
||||
const featureType = getUseCaseFeatures(useCase);
|
||||
|
||||
@@ -97,27 +97,21 @@ function generateReactCode(useCase: UseCase, skin: Skin, renderer: Renderer, pla
|
||||
mediaImport = `import { ${rendererComponent} } from '@videojs/react/media/${getRendererMediaSubpath(renderer)}';`;
|
||||
}
|
||||
|
||||
// Determine props based on renderer + playbackId
|
||||
const isMuxWithPlaybackId =
|
||||
(renderer === 'mux-video' || renderer === 'mux-audio' || renderer === 'mux-background-video') && playbackId;
|
||||
const propsInterface = isMuxWithPlaybackId
|
||||
? 'interface MyPlayerProps {\n playbackId: string;\n}'
|
||||
: 'interface MyPlayerProps {\n src: string;\n}';
|
||||
const destructuredProp = isMuxWithPlaybackId ? 'playbackId' : 'src';
|
||||
const rendererJsx = isMuxWithPlaybackId
|
||||
? `<${rendererComponent} playbackId={playbackId} />`
|
||||
: `<${rendererComponent} src={src} />`;
|
||||
// Determine props — mux variants use src with stream.mux.com URL
|
||||
const propsInterface = 'interface MyPlayerProps {\n src: string;\n}';
|
||||
const destructuredProp = 'src';
|
||||
const rendererJsx = `<${rendererComponent} src={src} />`;
|
||||
|
||||
const imports = [
|
||||
`import '${skinCssImport}';`,
|
||||
`import { createPlayer, features } from '@videojs/react';`,
|
||||
`import { createPlayer, ${featureType} } from '@videojs/react';`,
|
||||
presetImport,
|
||||
...(mediaImport ? [mediaImport] : []),
|
||||
].join('\n');
|
||||
|
||||
return `${imports}
|
||||
|
||||
const Player = createPlayer({ features: features.${featureType} });
|
||||
const Player = createPlayer({ features: ${featureType} });
|
||||
|
||||
${propsInterface}
|
||||
|
||||
@@ -136,7 +130,6 @@ export default function ReactCreateCodeBlock() {
|
||||
const $useCase = useStore(useCase);
|
||||
const $skin = useStore(skin);
|
||||
const $renderer = useStore(renderer);
|
||||
const $muxPlaybackId = useStore(muxPlaybackId);
|
||||
|
||||
return (
|
||||
<TabsRoot maxWidth={false}>
|
||||
@@ -146,7 +139,7 @@ export default function ReactCreateCodeBlock() {
|
||||
</Tab>
|
||||
</TabsList>
|
||||
<TabsPanel value="react" initial>
|
||||
<ClientCode code={generateReactCode($useCase, $skin, $renderer, $muxPlaybackId)} lang="tsx" />
|
||||
<ClientCode code={generateReactCode($useCase, $skin, $renderer)} lang="tsx" />
|
||||
</TabsPanel>
|
||||
</TabsRoot>
|
||||
);
|
||||
|
||||
@@ -1,21 +1,10 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import ClientCode from '@/components/Code/ClientCode';
|
||||
import { Tab, TabsList, TabsPanel, TabsRoot } from '@/components/Tabs';
|
||||
import type { Renderer } from '@/stores/installation';
|
||||
import { muxPlaybackId, renderer, sourceUrl } from '@/stores/installation';
|
||||
import { renderer, sourceUrl } from '@/stores/installation';
|
||||
|
||||
function generateUsageCode(renderer: Renderer, playbackId: string | null, url: string): string {
|
||||
const isMuxWithPlaybackId =
|
||||
(renderer === 'mux-video' || renderer === 'mux-audio' || renderer === 'mux-background-video') && playbackId;
|
||||
|
||||
let playerProp: string;
|
||||
if (isMuxWithPlaybackId) {
|
||||
playerProp = `playbackId="${playbackId}"`;
|
||||
} else if (url.trim()) {
|
||||
playerProp = `src="${url.trim()}"`;
|
||||
} else {
|
||||
playerProp = 'src="https://example.com/video.mp4"';
|
||||
}
|
||||
function generateUsageCode(url: string): string {
|
||||
const playerProp = url.trim() ? `src="${url.trim()}"` : 'src="https://example.com/video.mp4"';
|
||||
|
||||
return `import { MyPlayer } from '../components/player';
|
||||
|
||||
@@ -30,8 +19,7 @@ export const HomePage = () => {
|
||||
}
|
||||
|
||||
export default function ReactUsageCodeBlock() {
|
||||
const $renderer = useStore(renderer);
|
||||
const $muxPlaybackId = useStore(muxPlaybackId);
|
||||
useStore(renderer);
|
||||
const $sourceUrl = useStore(sourceUrl);
|
||||
|
||||
return (
|
||||
@@ -42,7 +30,7 @@ export default function ReactUsageCodeBlock() {
|
||||
</Tab>
|
||||
</TabsList>
|
||||
<TabsPanel value="react" initial>
|
||||
<ClientCode code={generateUsageCode($renderer, $muxPlaybackId, $sourceUrl)} lang="tsx" />
|
||||
<ClientCode code={generateUsageCode($sourceUrl)} lang="tsx" />
|
||||
</TabsPanel>
|
||||
</TabsRoot>
|
||||
);
|
||||
|
||||
@@ -2,24 +2,24 @@ import { useStore } from '@nanostores/react';
|
||||
import { useEffect } from 'react';
|
||||
import { Select, type SelectOption } from '@/components/Select';
|
||||
import type { Renderer, UseCase } from '@/stores/installation';
|
||||
import { muxPlaybackId, renderer, sourceUrl, useCase, VALID_RENDERERS } from '@/stores/installation';
|
||||
import { articleFor, detectRenderer, extractMuxPlaybackId } from '@/utils/installation/detect-renderer';
|
||||
import { renderer, sourceUrl, useCase, VALID_RENDERERS } from '@/stores/installation';
|
||||
import { articleFor, detectRenderer } from '@/utils/installation/detect-renderer';
|
||||
|
||||
const RENDERER_LABELS: Record<Renderer, string> = {
|
||||
'background-video': 'Background Video',
|
||||
cloudflare: 'Cloudflare',
|
||||
dash: 'DASH',
|
||||
// cloudflare: 'Cloudflare',
|
||||
// dash: 'DASH',
|
||||
hls: 'HLS',
|
||||
'html5-audio': 'HTML5 Audio',
|
||||
'html5-video': 'HTML5 Video',
|
||||
jwplayer: 'JW Player',
|
||||
'mux-audio': 'Mux',
|
||||
'mux-background-video': 'Mux Background Video',
|
||||
'mux-video': 'Mux',
|
||||
spotify: 'Spotify',
|
||||
vimeo: 'Vimeo',
|
||||
wistia: 'Wistia',
|
||||
youtube: 'YouTube',
|
||||
// jwplayer: 'JW Player',
|
||||
// 'mux-audio': 'Mux',
|
||||
// 'mux-background-video': 'Mux Background Video',
|
||||
// 'mux-video': 'Mux',
|
||||
// spotify: 'Spotify',
|
||||
// vimeo: 'Vimeo',
|
||||
// wistia: 'Wistia',
|
||||
// youtube: 'YouTube',
|
||||
};
|
||||
|
||||
function buildOptions(useCase: UseCase): SelectOption<Renderer>[] {
|
||||
@@ -36,16 +36,15 @@ export default function RendererSelect() {
|
||||
|
||||
const options = buildOptions($useCase);
|
||||
const detection = detectRenderer($sourceUrl, $useCase);
|
||||
const detectedRenderer = detection?.renderer ?? null;
|
||||
|
||||
// Auto-select renderer when detection or use case changes
|
||||
// Auto-select renderer when the detected renderer or use case changes.
|
||||
// Uses the primitive `detectedRenderer` string instead of the `detection`
|
||||
// object to avoid re-firing on every render (new object reference each time),
|
||||
// which would override manual dropdown selection.
|
||||
useEffect(() => {
|
||||
if (detection) {
|
||||
renderer.set(detection.renderer);
|
||||
|
||||
const playbackId = extractMuxPlaybackId($sourceUrl);
|
||||
if (playbackId) {
|
||||
muxPlaybackId.set(playbackId);
|
||||
}
|
||||
if (detectedRenderer) {
|
||||
renderer.set(detectedRenderer);
|
||||
} else {
|
||||
// No valid detection — ensure current renderer is valid for use case
|
||||
const current = renderer.get();
|
||||
@@ -54,7 +53,7 @@ export default function RendererSelect() {
|
||||
renderer.set(validRenderers[0]!);
|
||||
}
|
||||
}
|
||||
}, [detection, $sourceUrl, $useCase]);
|
||||
}, [detectedRenderer, $useCase]);
|
||||
|
||||
const showDetectionMatch = $sourceUrl.trim() && detection && detection.renderer === $renderer;
|
||||
const showDetectionSuggestion = $sourceUrl.trim() && detection && detection.renderer !== $renderer;
|
||||
|
||||
Reference in New Issue
Block a user