Files
netbird-docs/src/components/Video.jsx
Eduard Gert 96f3cb18d1 docs: add Control Center Draft Mode guide
Add a how-to page for the new Draft Mode in Control Center: build a
change on a working copy of the canvas, review the exact API requests,
and deploy everything as one batch. A single running example (giving
DevOps HTTPS access to a not-yet-installed staging server) carries
through entering a draft, the canvas toolbar, node interactions,
placeholder-peer installs, and Review & Deploy.

Along the way:
- Nest Control Center in the sidebar (Overview + Draft Mode) and update
  the overview page: Users view in the intro and quick start, an Edit
  Nodes section covering live edits vs Draft Mode, permissions notes
  including the Network Admin setup-key limitation, and a HashRedirect
  for the renamed #editing-policies-from-the-graph anchor.
- Add a shared <Video> component for screen recordings: lazy playback
  via IntersectionObserver, visible controls, preload="metadata", and
  no autoplay under prefers-reduced-motion.
- Optimize media: re-encode recordings (H.264 CRF 26, 30 fps,
  faststart, audio stripped) and losslessly recompress screenshots,
  cutting the page's media payload from 6.3 MB to 1.2 MB.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 12:22:21 +02:00

53 lines
1.4 KiB
JavaScript

import { useEffect, useRef } from 'react'
import clsx from 'clsx'
/**
* Looping screen-recording embed for docs pages.
*
* Recordings load lazily and play only while on screen: `preload="metadata"`
* avoids buffering full files up front, and an IntersectionObserver starts
* playback when the video scrolls into view and pauses it when it leaves.
* Controls stay visible so the loop can be paused (WCAG 2.2.2), and autoplay
* is skipped entirely for users who prefer reduced motion.
*
* Usage:
* <Video src="/docs-static/img/manage/example.mp4" label="What the recording shows" />
*/
export function Video({ src, label, className, ...props }) {
const ref = useRef(null)
useEffect(() => {
const video = ref.current
if (!video) return
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
video.play().catch(() => {})
} else {
video.pause()
}
},
{ threshold: 0.25 }
)
observer.observe(video)
return () => observer.disconnect()
}, [])
return (
<video
ref={ref}
src={src}
loop
muted
playsInline
controls
preload="metadata"
aria-label={label}
className={clsx('imagewrapper-big', className)}
{...props}
/>
)
}