mirror of
https://github.com/netbirdio/docs.git
synced 2026-09-02 05:01:27 +02:00
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>
This commit is contained in:
52
src/components/Video.jsx
Normal file
52
src/components/Video.jsx
Normal file
@@ -0,0 +1,52 @@
|
||||
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}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user