mirror of
https://github.com/netbirdio/docs.git
synced 2026-09-18 12:59:04 +02:00
docs: add Control Center Draft Mode guide (#942)
* 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> * fix: image zoom overlay flickering on close The closing fade-out ran without animation-fill-mode: forwards, so when the 200ms animation finished the overlay snapped back to full opacity until React's unmount timeout fired, flashing for a frame or two. Holding the animation end state covers that gap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: tighten Draft Mode intro Give the running example its own paragraph and drop the header-chrome description; the video right below it shows the same thing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: add Focus Mode section and group-from-selection video Document Focus Mode on the Control Center overview (right-click a node and choose Focus, or select it and press F) with two screenshots, and move the F shortcut prose there from the Draft Mode page. Add a recording of creating a group from a multi-peer selection to the Draft Mode page. New media compressed like the rest. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: correct Focus Mode shortcut order F is pressed first, then the node is selected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: drop setup-key caveat from Draft Mode permissions note The Network Admin limitation is already covered where it bites, in the placeholder install section. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: drop Agent Network disambiguation from Add Nodes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: reorder Assign Peers to Groups videos Show the drag-to-group recording right after the text it illustrates, then the group-from-selection flow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: remove change-type badge list from review section The review rows do not carry Add/Modify/Delete/Install badges. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: trim group-membership parenthetical from review example Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: react to prefers-reduced-motion changes in Video The reduced-motion check ran once on mount, so toggling the OS setting while the page was open either kept videos auto-playing or left them permanently inert. Listen for MediaQueryList changes: pause and drop the observer when reduced motion turns on, re-observe when it turns off. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
af75bc95ec
commit
e246829450
@@ -81,7 +81,14 @@ export const docsNavigation = [
|
||||
{
|
||||
title: 'MANAGE NETBIRD',
|
||||
links: [
|
||||
{ title: 'Control Center', href: '/manage/control-center' },
|
||||
{
|
||||
title: 'Control Center',
|
||||
isOpen: false,
|
||||
links: [
|
||||
{ title: 'Overview', href: '/manage/control-center' },
|
||||
{ title: 'Draft Mode', href: '/manage/control-center/draft-mode' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Peers',
|
||||
isOpen: false,
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
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
|
||||
|
||||
const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)')
|
||||
let observer = null
|
||||
|
||||
const observe = () => {
|
||||
observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
video.play().catch(() => {})
|
||||
} else {
|
||||
video.pause()
|
||||
}
|
||||
},
|
||||
{ threshold: 0.25 }
|
||||
)
|
||||
observer.observe(video)
|
||||
}
|
||||
|
||||
// React to the OS setting changing while the page is open.
|
||||
const handleMotionChange = () => {
|
||||
if (reducedMotion.matches) {
|
||||
observer?.disconnect()
|
||||
observer = null
|
||||
video.pause()
|
||||
} else if (!observer) {
|
||||
observe()
|
||||
}
|
||||
}
|
||||
|
||||
if (!reducedMotion.matches) observe()
|
||||
reducedMotion.addEventListener('change', handleMotionChange)
|
||||
|
||||
return () => {
|
||||
reducedMotion.removeEventListener('change', handleMotionChange)
|
||||
observer?.disconnect()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<video
|
||||
ref={ref}
|
||||
src={src}
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
controls
|
||||
preload="metadata"
|
||||
aria-label={label}
|
||||
className={clsx('imagewrapper-big', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -9,6 +9,7 @@ export { Button } from '@/components/Button'
|
||||
export { CodeGroup, Code as code, Pre as pre } from '@/components/Code'
|
||||
export { Badge } from '@/components/Badge'
|
||||
export { YouTube }
|
||||
export { Video } from '@/components/Video'
|
||||
|
||||
export const h2 = function H2(props) {
|
||||
return <Heading level={2} {...props} />
|
||||
|
||||
Reference in New Issue
Block a user