mirror of
https://github.com/zoriya/v10.git
synced 2026-08-15 18:34:22 +00:00
fix(website): resolve Safari hydration error
This commit is contained in:
@@ -5,6 +5,11 @@ import html from 'shiki/langs/html.mjs';
|
||||
import tsx from 'shiki/langs/tsx.mjs';
|
||||
import gruvboxLightHard from 'shiki/themes/gruvbox-light-hard.mjs';
|
||||
|
||||
// If you try importing more than one island with ClientCode in it,
|
||||
// Safari MAY throw a hydration error because of this top-level await.
|
||||
// https://github.com/withastro/astro/issues/10055
|
||||
// consolidate the ClientCodes into a single island to work around... for now :(
|
||||
|
||||
// eslint-disable-next-line antfu/no-top-level-await
|
||||
const highlighter: Highlighter = await createHighlighter({
|
||||
themes: [gruvboxLightHard],
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import type { Media, Skin } from '@/stores/homePageDemos';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { framework, media, skin } from '@/stores/homePageDemos';
|
||||
import ClientCode from './ClientCode';
|
||||
import ClientCode from '../ClientCode';
|
||||
|
||||
function generateHTMLCode(skin: Skin, media: Media): string {
|
||||
const skinTag = `${skin}-skin`;
|
||||
@@ -38,7 +38,7 @@ export const VideoPlayer = () => {
|
||||
interface Props {
|
||||
className?: string;
|
||||
}
|
||||
export default function HomePageBaseDemo({ className }: Props) {
|
||||
export default function BaseDemo({ className }: Props) {
|
||||
const $framework = useStore(framework);
|
||||
const $skin = useStore(skin);
|
||||
const $media = useStore(media);
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { Media, Skin } from '@/stores/homePageDemos';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { framework, media, skin } from '@/stores/homePageDemos';
|
||||
import ClientCode from '../ClientCode';
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
function generateHTMLCode(skin: Skin, media: Media): string {
|
||||
return `Coming soon`;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
function generateReactCode(skin: Skin, media: Media): string {
|
||||
return `Coming soon`;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
}
|
||||
export default function EjectDemo({ className }: Props) {
|
||||
const $framework = useStore(framework);
|
||||
const $skin = useStore(skin);
|
||||
const $media = useStore(media);
|
||||
|
||||
const code = $framework === 'html'
|
||||
? generateHTMLCode($skin, $media)
|
||||
: generateReactCode($skin, $media);
|
||||
|
||||
const lang = $framework === 'html' ? 'html' : 'tsx';
|
||||
|
||||
return (
|
||||
<ClientCode code={code} lang={lang} className={className} />
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import clsx from 'clsx';
|
||||
import BaseDemo from './Base';
|
||||
import EjectDemo from './Eject';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function HomePageDemo({ className }: Props) {
|
||||
return (
|
||||
<section className={clsx('grid gap-x-9 gap-y-6 lg:grid-cols-2', className)}>
|
||||
<section className="grid grid-rows-subgrid row-span-2 mb-6">
|
||||
<header className="max-w-3xl">
|
||||
<h2 className="text-h5 font-semibold lg:text-h4 mb-1">Assemble your player</h2>
|
||||
<p>Feel at home with your framework, skin, and media source</p>
|
||||
</header>
|
||||
<BaseDemo className="lg:h-89" />
|
||||
</section>
|
||||
<section className="grid grid-rows-subgrid row-span-2 mb-6">
|
||||
<header className="max-w-3xl">
|
||||
<h2 className="text-h5 font-semibold lg:text-h4 mb-1">Take full control</h2>
|
||||
<p>Make your player truly your own with fully-editable components</p>
|
||||
</header>
|
||||
<EjectDemo className="lg:h-89" />
|
||||
</section>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import type { Media, Skin } from '@/stores/homePageDemos';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { framework, media, skin } from '@/stores/homePageDemos';
|
||||
import ClientCode from './ClientCode';
|
||||
|
||||
function generateHTMLCode(skin: Skin, media: Media): string {
|
||||
const skinTag = `${skin}-skin`;
|
||||
const mediaTag = media;
|
||||
const videoExtension = media === 'hls-video' ? 'm3u8' : 'mp4';
|
||||
|
||||
return `<video-provider>
|
||||
<${skinTag}>
|
||||
<${mediaTag} src="https://example.com/video.${videoExtension}"></${mediaTag}>
|
||||
</${skinTag}>
|
||||
</video-provider>`;
|
||||
}
|
||||
|
||||
function generateReactCode(skin: Skin, media: Media): string {
|
||||
const skinComponent = skin === 'frosted' ? 'FrostedSkin' : 'MinimalSkin';
|
||||
const mediaComponent = media === 'video' ? 'Video' : 'HLSVideo';
|
||||
const skinImport = skin === 'frosted' ? 'frosted' : 'minimal';
|
||||
const videoExtension = media === 'hls-video' ? 'm3u8' : 'mp4';
|
||||
|
||||
return `import { VideoProvider, ${mediaComponent} } from '@vjs-10/react';
|
||||
import { ${skinComponent} } from '@vjs-10/react/skins/${skinImport}';
|
||||
|
||||
export const VideoPlayer = () => {
|
||||
return (
|
||||
<VideoProvider>
|
||||
<${skinComponent}>
|
||||
<${mediaComponent} src="https://example.com/video.${videoExtension}" />
|
||||
</${skinComponent}>
|
||||
</VideoProvider>
|
||||
);
|
||||
};`;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
}
|
||||
export default function HomePageEjectDemo({ className }: Props) {
|
||||
const $framework = useStore(framework);
|
||||
const $skin = useStore(skin);
|
||||
const $media = useStore(media);
|
||||
|
||||
const code = $framework === 'html'
|
||||
? generateHTMLCode($skin, $media)
|
||||
: generateReactCode($skin, $media);
|
||||
|
||||
const lang = $framework === 'html' ? 'html' : 'tsx';
|
||||
|
||||
return (
|
||||
<ClientCode code={code} lang={lang} className={className} />
|
||||
);
|
||||
}
|
||||
@@ -6,8 +6,7 @@ import NavBar from '@/components/NavBar/NavBar.astro';
|
||||
import Footer from '@/components/Footer.astro';
|
||||
import { SITE_DESCRIPTION, SITE_TITLE } from '@/consts';
|
||||
import Base from '@/layouts/Base.astro';
|
||||
import HomePageBaseDemo from '@/components/HomePageBaseDemo';
|
||||
import HomePageEjectDemo from '@/components/HomePageEjectDemo';
|
||||
import HomePageDemo from '@/components/HomePageDemo';
|
||||
import HomePageControls from '@/components/home/HomePageControls';
|
||||
import { PLAYBACK_ID } from '@/components/home/config';
|
||||
import { CircleCheck, Clock } from 'lucide-react';
|
||||
@@ -44,22 +43,7 @@ const poster = `https://image.mux.com/${PLAYBACK_ID}/thumbnail.webp?time=0`;
|
||||
<!-- padding corresponds to negative margin on player -->
|
||||
<main class="@container pt-11 pb-36 md:pt-21 lg:pt-32 px-6 md:px-10 w-full max-w-7xl mx-auto min-h-64">
|
||||
<HomePageControls client:idle className="col-span-full my-10 sm:mb-20" />
|
||||
<section class="grid gap-x-9 gap-y-6 lg:grid-cols-2 mb-6 lg:mb-30">
|
||||
<section class="grid grid-rows-subgrid row-span-2 mb-6">
|
||||
<header class="max-w-3xl">
|
||||
<h2 class="text-h5 font-semibold lg:text-h4 mb-1">Assemble your player</h2>
|
||||
<p>Feel at home with your framework, skin, and media source</p>
|
||||
</header>
|
||||
<HomePageBaseDemo client:idle className="lg:h-89" />
|
||||
</section>
|
||||
<section class="grid grid-rows-subgrid row-span-2 mb-6">
|
||||
<header class="max-w-3xl">
|
||||
<h2 class="text-h5 font-semibold lg:text-h4 mb-1">Take full control</h2>
|
||||
<p>Make your player truly your own with fully-editable components</p>
|
||||
</header>
|
||||
<HomePageEjectDemo client:idle className="lg:h-89" />
|
||||
</section>
|
||||
</section>
|
||||
<HomePageDemo client:idle className="mb-6 lg:mb-30" />
|
||||
<section class="rounded-3xl">
|
||||
<header class="max-w-3xl mb-3">
|
||||
<h2 class="text-h5 font-semibold lg:text-h4">Under construction</h2>
|
||||
|
||||
Reference in New Issue
Block a user