feat(nx-dev): update terminal markdown embeds
This commit is contained in:
parent
05cbce0de8
commit
9610fdd90c
@ -67,6 +67,16 @@ You can add specific languages and a filename on the code snippet displayed.
|
|||||||
```
|
```
|
||||||
````
|
````
|
||||||
|
|
||||||
|
#### Terminal command
|
||||||
|
|
||||||
|
To display a terminal command, use:
|
||||||
|
|
||||||
|
````
|
||||||
|
```shell
|
||||||
|
npx nx build
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
#### Terminal Output
|
#### Terminal Output
|
||||||
|
|
||||||
You can display your terminal output with a dedicated component the same way you would show code.
|
You can display your terminal output with a dedicated component the same way you would show code.
|
||||||
@ -85,6 +95,14 @@ You can optionally also pass a `path` like
|
|||||||
```
|
```
|
||||||
````
|
````
|
||||||
|
|
||||||
|
#### Terminal Video Output
|
||||||
|
|
||||||
|
You can have a more dynamic visualization of a terminal output by using the following component:
|
||||||
|
|
||||||
|
```
|
||||||
|
{% terminal-video src="/documentation/shared/images/caching/cache-terminal-animation.mp4" /%}
|
||||||
|
```
|
||||||
|
|
||||||
#### Custom iframes
|
#### Custom iframes
|
||||||
|
|
||||||
We can display a special iframe and setting its width inside the document.
|
We can display a special iframe and setting its width inside the document.
|
||||||
|
|||||||
@ -5,24 +5,30 @@ Create a new Nx workspace using the following command:
|
|||||||
{% tabs %}
|
{% tabs %}
|
||||||
{% tab label="npm" %}
|
{% tab label="npm" %}
|
||||||
|
|
||||||
{% terminal-command command="npx create-nx-workspace" /%}
|
```shell
|
||||||
|
npx create-nx-workspace
|
||||||
|
```
|
||||||
|
|
||||||
{% /tab %}
|
{% /tab %}
|
||||||
{% tab label="yarn" %}
|
{% tab label="yarn" %}
|
||||||
|
|
||||||
{% terminal-command command="npx create-nx-workspace --pm yarn" /%}
|
```shell
|
||||||
|
npx create-nx-workspace --pm yarn
|
||||||
|
```
|
||||||
|
|
||||||
{% /tab %}
|
{% /tab %}
|
||||||
{% tab label="pnpm" %}
|
{% tab label="pnpm" %}
|
||||||
|
|
||||||
{% terminal-command command="npx create-nx-workspace --pm pnpm" /%}
|
```shell
|
||||||
|
npx create-nx-workspace --pm pnpm
|
||||||
|
```
|
||||||
|
|
||||||
{% /tab %}
|
{% /tab %}
|
||||||
{% /tabs %}
|
{% /tabs %}
|
||||||
|
|
||||||
This will guide you through the setup, asking whether you want a monorepo or a standalone app and whether you want to start with a blank or a preconfigured setup.
|
This will guide you through the setup, asking whether you want a monorepo or a standalone app and whether you want to start with a blank or a preconfigured setup.
|
||||||
|
|
||||||
```{% command="npx create-nx-workspace" %}
|
```{% command="npx create-nx-workspace" path="~" %}
|
||||||
|
|
||||||
> NX Let's create a new workspace [https://nx.dev/getting-started/intro]
|
> NX Let's create a new workspace [https://nx.dev/getting-started/intro]
|
||||||
|
|
||||||
@ -48,7 +54,9 @@ Learn more about [running tasks](/core-features/run-tasks).
|
|||||||
|
|
||||||
If you want to add Nx to an existing repository run:
|
If you want to add Nx to an existing repository run:
|
||||||
|
|
||||||
{% terminal-command command="npx nx@latest init" /%}
|
```shell
|
||||||
|
npx nx@latest init
|
||||||
|
```
|
||||||
|
|
||||||
You can also manually install the nx NPM package and create a [nx.json](https://nx.dev/reference/nx-json) to configure it. Learn more about [adopting Nx in an existing project](/recipes/adopting-nx)
|
You can also manually install the nx NPM package and create a [nx.json](https://nx.dev/reference/nx-json) to configure it. Learn more about [adopting Nx in an existing project](/recipes/adopting-nx)
|
||||||
|
|
||||||
@ -59,17 +67,23 @@ You can install Nx globally. Depending on your package manager, use one of the f
|
|||||||
{% tabs %}
|
{% tabs %}
|
||||||
{% tab label="npm" %}
|
{% tab label="npm" %}
|
||||||
|
|
||||||
{% terminal-command command="npm install --global nx@latest" /%}
|
```shell
|
||||||
|
npm install --global nx@latest
|
||||||
|
```
|
||||||
|
|
||||||
{% /tab %}
|
{% /tab %}
|
||||||
{% tab label="yarn" %}
|
{% tab label="yarn" %}
|
||||||
|
|
||||||
{% terminal-command command="yarn global add nx@latest" /%}
|
```shell
|
||||||
|
yarn global add nx@latest
|
||||||
|
```
|
||||||
|
|
||||||
{% /tab %}
|
{% /tab %}
|
||||||
{% tab label="pnpm" %}
|
{% tab label="pnpm" %}
|
||||||
|
|
||||||
{% terminal-command command="pnpm install --global nx@latest" /%}
|
```shell
|
||||||
|
pnpm install --global nx@latest
|
||||||
|
```
|
||||||
|
|
||||||
{% /tab %}
|
{% /tab %}
|
||||||
{% /tabs %}
|
{% /tabs %}
|
||||||
|
|||||||
@ -7,17 +7,23 @@ If instead you want to jump right into it, run the following command. It will gu
|
|||||||
{% tabs %}
|
{% tabs %}
|
||||||
{% tab label="npm" %}
|
{% tab label="npm" %}
|
||||||
|
|
||||||
{% terminal-command command="npx create-nx-workspace" /%}
|
```shell
|
||||||
|
npx create-nx-workspace
|
||||||
|
```
|
||||||
|
|
||||||
{% /tab %}
|
{% /tab %}
|
||||||
{% tab label="yarn" %}
|
{% tab label="yarn" %}
|
||||||
|
|
||||||
{% terminal-command command="npx create-nx-workspace --pm yarn" /%}
|
```shell
|
||||||
|
npx create-nx-workspace --pm yarn
|
||||||
|
```
|
||||||
|
|
||||||
{% /tab %}
|
{% /tab %}
|
||||||
{% tab label="pnpm" %}
|
{% tab label="pnpm" %}
|
||||||
|
|
||||||
{% terminal-command command="npx create-nx-workspace --pm pnpm" /%}
|
```shell
|
||||||
|
npx create-nx-workspace --pm pnpm
|
||||||
|
```
|
||||||
|
|
||||||
{% /tab %}
|
{% /tab %}
|
||||||
{% /tabs %}
|
{% /tabs %}
|
||||||
@ -92,7 +98,9 @@ A modern Node server with scaffolding for Express, Fastify or Koa. There's also
|
|||||||
|
|
||||||
If you have an existing project and want to adopt Nx or migrate to Nx just run the following command which guides you through the migration process:
|
If you have an existing project and want to adopt Nx or migrate to Nx just run the following command which guides you through the migration process:
|
||||||
|
|
||||||
{% terminal-command command="npx nx@latest init" /%}
|
```shell
|
||||||
|
npx nx@latest init
|
||||||
|
```
|
||||||
|
|
||||||
Alternatively, here are some recipes that give you more details based on the technology stack you're using:
|
Alternatively, here are some recipes that give you more details based on the technology stack you're using:
|
||||||
|
|
||||||
|
|||||||
@ -39,9 +39,9 @@ import { Tab, Tabs } from './lib/tags/tabs.component';
|
|||||||
import { tab, tabs } from './lib/tags/tabs.schema';
|
import { tab, tabs } from './lib/tags/tabs.schema';
|
||||||
import { YouTube, youtube } from './lib/tags/youtube.component';
|
import { YouTube, youtube } from './lib/tags/youtube.component';
|
||||||
import {
|
import {
|
||||||
TerminalCommand,
|
TerminalVideo,
|
||||||
terminalCommand,
|
terminalVideo,
|
||||||
} from './lib/tags/terminal-command.component';
|
} from './lib/tags/terminal-video.component';
|
||||||
import { VideoLink, videoLink } from './lib/tags/video-link.component';
|
import { VideoLink, videoLink } from './lib/tags/video-link.component';
|
||||||
|
|
||||||
// TODO fix this export
|
// TODO fix this export
|
||||||
@ -74,7 +74,7 @@ export const getMarkdocCustomConfig = (
|
|||||||
tabs,
|
tabs,
|
||||||
'title-card': titleCard,
|
'title-card': titleCard,
|
||||||
youtube,
|
youtube,
|
||||||
'terminal-command': terminalCommand,
|
'terminal-video': terminalVideo,
|
||||||
'video-link': videoLink,
|
'video-link': videoLink,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -98,7 +98,7 @@ export const getMarkdocCustomConfig = (
|
|||||||
Tabs,
|
Tabs,
|
||||||
TitleCard,
|
TitleCard,
|
||||||
YouTube,
|
YouTube,
|
||||||
TerminalCommand,
|
TerminalVideo,
|
||||||
VideoLink,
|
VideoLink,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -27,9 +27,18 @@ function CodeWrapper(options: {
|
|||||||
command: string;
|
command: string;
|
||||||
path: string;
|
path: string;
|
||||||
isMessageBelow: boolean;
|
isMessageBelow: boolean;
|
||||||
|
language: string;
|
||||||
|
children: string; // intentionally typed as such
|
||||||
}): ({ children }: { children: ReactNode }) => JSX.Element {
|
}): ({ children }: { children: ReactNode }) => JSX.Element {
|
||||||
return ({ children }: { children: ReactNode }) =>
|
return ({ children }: { children: ReactNode }) =>
|
||||||
options.command ? (
|
options.language === 'shell' ? (
|
||||||
|
<TerminalOutput
|
||||||
|
command={options.children}
|
||||||
|
path=""
|
||||||
|
content={null}
|
||||||
|
isMessageBelow={false}
|
||||||
|
/>
|
||||||
|
) : options.command ? (
|
||||||
<TerminalOutput
|
<TerminalOutput
|
||||||
content={children}
|
content={children}
|
||||||
command={options.command}
|
command={options.command}
|
||||||
@ -51,12 +60,14 @@ export function Fence({
|
|||||||
path,
|
path,
|
||||||
fileName,
|
fileName,
|
||||||
language,
|
language,
|
||||||
|
enableCopy,
|
||||||
}: {
|
}: {
|
||||||
children: string;
|
children: string;
|
||||||
command: string;
|
command: string;
|
||||||
path: string;
|
path: string;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
language: string;
|
language: string;
|
||||||
|
enableCopy: boolean;
|
||||||
}) {
|
}) {
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -76,6 +87,7 @@ export function Fence({
|
|||||||
<div className="my-8 w-full">
|
<div className="my-8 w-full">
|
||||||
<div className="code-block group relative w-full">
|
<div className="code-block group relative w-full">
|
||||||
<div>
|
<div>
|
||||||
|
{enableCopy && enableCopy === true && (
|
||||||
<CopyToClipboard
|
<CopyToClipboard
|
||||||
text={command && command !== '' ? command : children}
|
text={command && command !== '' ? command : children}
|
||||||
onCopy={() => {
|
onCopy={() => {
|
||||||
@ -93,6 +105,7 @@ export function Fence({
|
|||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</CopyToClipboard>
|
</CopyToClipboard>
|
||||||
|
)}
|
||||||
<SyntaxHighlighter
|
<SyntaxHighlighter
|
||||||
useInlineStyles={false}
|
useInlineStyles={false}
|
||||||
language={resolveLanguage(language)}
|
language={resolveLanguage(language)}
|
||||||
@ -102,6 +115,8 @@ export function Fence({
|
|||||||
command,
|
command,
|
||||||
path,
|
path,
|
||||||
isMessageBelow: showRescopeMessage,
|
isMessageBelow: showRescopeMessage,
|
||||||
|
language,
|
||||||
|
children,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
{showRescopeMessage && (
|
{showRescopeMessage && (
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export const fence: Schema = {
|
|||||||
command: { type: 'String', default: '' },
|
command: { type: 'String', default: '' },
|
||||||
path: { type: 'String', default: '~/workspace' },
|
path: { type: 'String', default: '~/workspace' },
|
||||||
process: { type: 'Boolean', render: false, default: true },
|
process: { type: 'Boolean', render: false, default: true },
|
||||||
|
enableCopy: { type: 'Boolean', default: true },
|
||||||
},
|
},
|
||||||
transform(node, config) {
|
transform(node, config) {
|
||||||
const attributes = node.transformAttributes(config);
|
const attributes = node.transformAttributes(config);
|
||||||
@ -1,6 +1,5 @@
|
|||||||
import { cx } from '@nx/nx-dev/ui-primitives';
|
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { VideoLoop } from '../../tags/video-loop.component';
|
import { TerminalShellWrapper } from './terminal-shell.component';
|
||||||
|
|
||||||
export function TerminalOutput({
|
export function TerminalOutput({
|
||||||
content,
|
content,
|
||||||
@ -13,24 +12,8 @@ export function TerminalOutput({
|
|||||||
isMessageBelow: boolean;
|
isMessageBelow: boolean;
|
||||||
path: string;
|
path: string;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const isVideo = command.indexOf('.mp4') > -1;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<TerminalShellWrapper isMessageBelow={isMessageBelow}>
|
||||||
className={cx(
|
|
||||||
'hljs not-prose w-full overflow-x-auto border border-slate-200 bg-slate-50/50 font-mono text-sm dark:border-slate-700 dark:bg-slate-800/60',
|
|
||||||
isMessageBelow ? 'rounded-t-lg border-b-0' : 'rounded-lg'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="relative flex justify-center p-2 border-b border-slate-200 bg-slate-100/50 text-slate-400 dark:border-slate-700 dark:bg-slate-700/50 dark:text-slate-500">
|
|
||||||
<div className="absolute flex items-center gap-2 left-2 top-3">
|
|
||||||
<span className="w-2 h-2 bg-red-400 rounded-full dark:bg-red-600" />
|
|
||||||
<span className="w-2 h-2 bg-yellow-400 rounded-full dark:bg-yellow-600" />
|
|
||||||
<span className="w-2 h-2 bg-green-400 rounded-full dark:bg-green-600" />
|
|
||||||
</div>
|
|
||||||
<span className="h-5"></span>
|
|
||||||
</div>
|
|
||||||
{!isVideo && (
|
|
||||||
<div className="p-4 pt-2 overflow-x-auto">
|
<div className="p-4 pt-2 overflow-x-auto">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<p className="mt-0.5">
|
<p className="mt-0.5">
|
||||||
@ -45,12 +28,6 @@ export function TerminalOutput({
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex not-prose">{content}</div>
|
<div className="flex not-prose">{content}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</TerminalShellWrapper>
|
||||||
{isVideo && (
|
|
||||||
<div className="overflow-x-auto">
|
|
||||||
<VideoLoop src={command}></VideoLoop>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
import { cx } from '@nx/nx-dev/ui-primitives';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
export function TerminalShellWrapper({
|
||||||
|
isMessageBelow,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
isMessageBelow: boolean;
|
||||||
|
children: ReactNode;
|
||||||
|
}): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
'hljs not-prose w-full overflow-x-auto border border-slate-200 bg-slate-50/50 font-mono text-sm dark:border-slate-700 dark:bg-slate-800/60',
|
||||||
|
isMessageBelow ? 'rounded-t-lg border-b-0' : 'rounded-lg'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="relative flex justify-center p-2 border-b border-slate-200 bg-slate-100/50 text-slate-400 dark:border-slate-700 dark:bg-slate-700/50 dark:text-slate-500">
|
||||||
|
<div className="absolute flex items-center gap-2 left-2 top-3">
|
||||||
|
<span className="w-2 h-2 bg-red-400 rounded-full dark:bg-red-600" />
|
||||||
|
<span className="w-2 h-2 bg-yellow-400 rounded-full dark:bg-yellow-600" />
|
||||||
|
<span className="w-2 h-2 bg-green-400 rounded-full dark:bg-green-600" />
|
||||||
|
</div>
|
||||||
|
<span className="h-5"></span>
|
||||||
|
</div>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
55
nx-dev/ui-markdoc/src/lib/tags/svg-animation.component.tsx
Normal file
55
nx-dev/ui-markdoc/src/lib/tags/svg-animation.component.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { Schema } from '@markdoc/markdoc';
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
export const svgAnimation: Schema = {
|
||||||
|
render: 'SvgAnimation',
|
||||||
|
attributes: {
|
||||||
|
src: {
|
||||||
|
type: 'String',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
title: {
|
||||||
|
type: 'String',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function SvgAnimation({
|
||||||
|
src,
|
||||||
|
title,
|
||||||
|
}: {
|
||||||
|
src: string;
|
||||||
|
title: string;
|
||||||
|
}): JSX.Element {
|
||||||
|
const objectRef = useRef<HTMLObjectElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (objectRef.current) {
|
||||||
|
fetch(src)
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then((svgContent) => {
|
||||||
|
objectRef.current!.data = `data:image/svg+xml,${encodeURIComponent(
|
||||||
|
svgContent
|
||||||
|
)}`;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error fetching SVG:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [src]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full rounded-md border border-slate-100 bg-slate-50/20 p-4 dark:border-slate-800 dark:bg-slate-800/60">
|
||||||
|
<object
|
||||||
|
ref={objectRef}
|
||||||
|
type="image/svg+xml"
|
||||||
|
title={title}
|
||||||
|
className="rounded-sm bg-white p-2 ring-1 ring-slate-50 dark:bg-slate-800/80 dark:ring-slate-800"
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</object>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,33 +0,0 @@
|
|||||||
import { Schema } from '@markdoc/markdoc';
|
|
||||||
import { TerminalOutput } from '../nodes/fences/terminal-output.component';
|
|
||||||
|
|
||||||
export const terminalCommand: Schema = {
|
|
||||||
render: 'TerminalCommand',
|
|
||||||
attributes: {
|
|
||||||
command: {
|
|
||||||
type: 'String',
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
path: {
|
|
||||||
type: 'String',
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export function TerminalCommand({
|
|
||||||
command,
|
|
||||||
path,
|
|
||||||
}: {
|
|
||||||
command: string;
|
|
||||||
path: string;
|
|
||||||
}): JSX.Element {
|
|
||||||
return (
|
|
||||||
<TerminalOutput
|
|
||||||
command={command}
|
|
||||||
path={path}
|
|
||||||
content={null}
|
|
||||||
isMessageBelow={false}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
33
nx-dev/ui-markdoc/src/lib/tags/terminal-video.component.tsx
Normal file
33
nx-dev/ui-markdoc/src/lib/tags/terminal-video.component.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { VideoLoop } from './video-loop.component';
|
||||||
|
import { Schema } from '@markdoc/markdoc';
|
||||||
|
import { TerminalShellWrapper } from '../nodes/fences/terminal-shell.component';
|
||||||
|
|
||||||
|
export const terminalVideo: Schema = {
|
||||||
|
render: 'TerminalVideo',
|
||||||
|
attributes: {
|
||||||
|
src: {
|
||||||
|
type: 'String',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
alt: {
|
||||||
|
type: 'String',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function TerminalVideo({
|
||||||
|
src,
|
||||||
|
alt,
|
||||||
|
}: {
|
||||||
|
src: string;
|
||||||
|
alt: string;
|
||||||
|
}): JSX.Element {
|
||||||
|
return (
|
||||||
|
<TerminalShellWrapper isMessageBelow={false}>
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<VideoLoop src={src} alt={alt}></VideoLoop>
|
||||||
|
</div>
|
||||||
|
</TerminalShellWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,22 +1,17 @@
|
|||||||
import { Schema } from '@markdoc/markdoc';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useEffect, useRef } from 'react';
|
|
||||||
|
|
||||||
export const videoLoop: Schema = {
|
export function VideoLoop({
|
||||||
render: 'VideoLoop',
|
src,
|
||||||
attributes: {
|
alt,
|
||||||
src: {
|
}: {
|
||||||
type: 'String',
|
src: string;
|
||||||
required: true,
|
alt: string;
|
||||||
},
|
}): JSX.Element {
|
||||||
},
|
const videoRef = useRef<HTMLVideoElement | null>(null);
|
||||||
};
|
|
||||||
|
|
||||||
export function VideoLoop({ src }: { src: string }): JSX.Element {
|
|
||||||
const videoRef = useRef(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let observer: IntersectionObserver;
|
let observer: IntersectionObserver;
|
||||||
let videoElement = videoRef.current as HTMLVideoElement | null;
|
let videoElement = videoRef.current;
|
||||||
|
|
||||||
if (videoElement) {
|
if (videoElement) {
|
||||||
observer = new IntersectionObserver(
|
observer = new IntersectionObserver(
|
||||||
@ -48,6 +43,13 @@ export function VideoLoop({ src }: { src: string }): JSX.Element {
|
|||||||
return (
|
return (
|
||||||
<video ref={videoRef} autoPlay muted loop>
|
<video ref={videoRef} autoPlay muted loop>
|
||||||
<source src={src} type="video/mp4" />
|
<source src={src} type="video/mp4" />
|
||||||
|
<div className="text-center p-4">
|
||||||
|
<p className="font-bold pb-3">
|
||||||
|
Your browser does not support the video tag. Here is a description of
|
||||||
|
the video:
|
||||||
|
</p>
|
||||||
|
<p>{alt}</p>
|
||||||
|
</div>
|
||||||
</video>
|
</video>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user