From ea4face7dc9474c2df7b10f09d004eb9ac80bde1 Mon Sep 17 00:00:00 2001 From: winoffrg Date: Sat, 9 May 2026 23:17:00 +0530 Subject: [PATCH 1/5] feat: updated docs and added player presets --- .gitignore | 2 + apps/www/app/docs/[[...slug]]/page.tsx | 2 +- apps/www/components/codeblock.tsx | 4 +- .../components/component-preview-control.tsx | 25 +- apps/www/components/component-preview.tsx | 81 ++--- .../stream-panel/custom-overlay.tsx | 230 ++++++++++++++ apps/www/components/stream-panel/index.ts | 4 + .../components/stream-panel/overlay-shell.tsx | 52 ++++ .../components/stream-panel/panel-popover.tsx | 292 ++++++++++++++++++ .../components/stream-panel/panel-slider.tsx | 146 +++++++++ .../stream-panel/presets-overlay.tsx | 77 +++++ apps/www/components/stream-panel/provider.tsx | 42 +++ .../components/stream-panel/saved-overlay.tsx | 61 ++++ .../stream-panel/use-stream-panel-sync.ts | 93 ++++++ apps/www/components/ui/dropdown-menu.tsx | 236 +++++++------- apps/www/components/ui/field.tsx | 292 ++++++++++++++++++ apps/www/components/ui/label.tsx | 24 ++ apps/www/components/ui/popover.tsx | 110 +++++++ apps/www/components/ui/select.tsx | 193 ++++++------ apps/www/components/ui/textarea.tsx | 29 ++ apps/www/components/ui/toggle-group.tsx | 43 +-- .../components/youtube-music-hover-player.tsx | 2 +- apps/www/lib/docs-dial-store.ts | 67 ++++ apps/www/lib/stream-presets.ts | 146 +++++++++ apps/www/package.json | 2 +- .../default/examples/player-root-demo.tsx | 280 +++++++++++++---- .../default/internal/custom-demo-controls.tsx | 131 +++----- .../registry/default/ui/playback-control.tsx | 4 +- apps/www/registry/pro | 2 +- bun.lock | 26 +- 30 files changed, 2275 insertions(+), 423 deletions(-) create mode 100644 apps/www/components/stream-panel/custom-overlay.tsx create mode 100644 apps/www/components/stream-panel/index.ts create mode 100644 apps/www/components/stream-panel/overlay-shell.tsx create mode 100644 apps/www/components/stream-panel/panel-popover.tsx create mode 100644 apps/www/components/stream-panel/panel-slider.tsx create mode 100644 apps/www/components/stream-panel/presets-overlay.tsx create mode 100644 apps/www/components/stream-panel/provider.tsx create mode 100644 apps/www/components/stream-panel/saved-overlay.tsx create mode 100644 apps/www/components/stream-panel/use-stream-panel-sync.ts create mode 100644 apps/www/components/ui/field.tsx create mode 100644 apps/www/components/ui/label.tsx create mode 100644 apps/www/components/ui/popover.tsx create mode 100644 apps/www/components/ui/textarea.tsx create mode 100644 apps/www/lib/docs-dial-store.ts create mode 100644 apps/www/lib/stream-presets.ts diff --git a/.gitignore b/.gitignore index d6cb1d9c..6c833f6d 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,5 @@ apps/www/public/r/* apps/www/registry.json apps/www/registry-pro.json apps/www/registry/__index__.tsx + +.claude diff --git a/apps/www/app/docs/[[...slug]]/page.tsx b/apps/www/app/docs/[[...slug]]/page.tsx index a16bf139..b5bd3140 100644 --- a/apps/www/app/docs/[[...slug]]/page.tsx +++ b/apps/www/app/docs/[[...slug]]/page.tsx @@ -46,7 +46,7 @@ export default async function Page(props: { {page.data.title} {page.data.description} -
+
diff --git a/apps/www/components/component-preview-control.tsx b/apps/www/components/component-preview-control.tsx index cd7daaaa..3017ee3a 100644 --- a/apps/www/components/component-preview-control.tsx +++ b/apps/www/components/component-preview-control.tsx @@ -1,7 +1,7 @@ "use client" import * as TabsPrimitive from "@radix-ui/react-tabs" -import { motion } from "motion/react" +import { AnimatePresence, motion } from "motion/react" import * as React from "react" import { Tabs, TabsList } from "@/components/ui/tabs" @@ -11,14 +11,17 @@ interface ComponentPreviewControlProps { children: React.ReactNode className?: string hideCode?: boolean + trailingSlot?: React.ReactNode } export function ComponentPreviewControl({ children, className, hideCode = false, + trailingSlot, }: ComponentPreviewControlProps) { const [activeTab, setActiveTab] = React.useState("preview") + const childArray = React.Children.toArray(children) return ( )} + {trailingSlot ? ( +
{trailingSlot}
+ ) : null} +
+
+ + + {childArray} + +
- {children} ) } diff --git a/apps/www/components/component-preview.tsx b/apps/www/components/component-preview.tsx index 6cbac11d..37985baa 100644 --- a/apps/www/components/component-preview.tsx +++ b/apps/www/components/component-preview.tsx @@ -43,17 +43,12 @@ export async function ComponentPreview({ const filePath = path.join(Component?.files?.[0]?.path) const fileContent = await fs.promises.readFile(filePath, "utf-8") const fileName = path.basename(filePath) - const PreviewComponent = withPlayer ? PlayerLayoutDemo : React.Fragment const rendered = await highlight(fileContent, { components: { pre: (props) =>
,
     },
     lang: "tsx",
-    themes: {
-      dark: "min-dark",
-      light: "github-light",
-    },
   })
 
   return (
@@ -61,39 +56,53 @@ export async function ComponentPreview({
       className={cn("group relative my-4 mb-12 flex flex-col space-y-2")}
       {...props}
     >
-      
-        
-        
-          
+          }
+          overlayChildren={overlayChildren}
+          type={type}
+        >
+          
+        
+      ) : (
+        
+          
-        
-      
+            
+ +
+ + + + {rendered} + + + + )}
) } diff --git a/apps/www/components/stream-panel/custom-overlay.tsx b/apps/www/components/stream-panel/custom-overlay.tsx new file mode 100644 index 00000000..f89d8c63 --- /dev/null +++ b/apps/www/components/stream-panel/custom-overlay.tsx @@ -0,0 +1,230 @@ +"use client" + +import { AnimatePresence, motion } from "motion/react" +import React, { useState } from "react" + +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Textarea } from "@/components/ui/textarea" +import { useDocsDialStore } from "@/lib/docs-dial-store" +import { cn } from "@/lib/utils" + +import { OverlayShell } from "./overlay-shell" + +interface CustomOverlayProps { + onBack: () => void + onLoad: (src: string, config?: string) => void + show: boolean +} + +export function CustomOverlay({ onBack, onLoad, show }: CustomOverlayProps) { + const store = useDocsDialStore() + const [urlError, setUrlError] = useState(false) + const [configError, setConfigError] = useState(false) + const [showSave, setShowSave] = useState(false) + const [saveName, setSaveName] = useState("") + + const isValidUrl = React.useMemo(() => { + const src = store.customSrc.trim() + if (!src) return false + try { + const url = new URL(src) + return url.protocol === "http:" || url.protocol === "https:" + } catch { + return false + } + }, [store.customSrc]) + + const isValidConfig = React.useMemo(() => { + const config = store.customConfig.trim() + if (!config) return true + try { + JSON.parse(config) + return true + } catch { + return false + } + }, [store.customConfig]) + + const canLoad = isValidUrl && isValidConfig + const canSave = canLoad && saveName.trim().length > 0 + + const handleUrlChange = (value: string) => { + store.setCustomSrc(value) + if (value.trim()) { + try { + const url = new URL(value.trim()) + setUrlError(url.protocol !== "http:" && url.protocol !== "https:") + } catch { + setUrlError(true) + } + } else { + setUrlError(false) + } + } + + const handleConfigChange = (value: string) => { + store.setCustomConfig(value) + if (value.trim()) { + try { + JSON.parse(value.trim()) + setConfigError(false) + } catch { + setConfigError(true) + } + } else { + setConfigError(false) + } + } + + const handleConfigPaste = (e: React.ClipboardEvent) => { + const pasted = e.clipboardData.getData("text") + try { + const parsed = JSON.parse(pasted) + e.preventDefault() + store.setCustomConfig(JSON.stringify(parsed, null, 2)) + setConfigError(false) + } catch { + // not valid JSON, let default paste happen + } + } + + const handleLoad = () => { + if (!canLoad) return + onLoad(store.customSrc.trim(), store.customConfig.trim() || undefined) + } + + const handleSave = () => { + if (!canSave) return + store.saveStream({ + config: store.customConfig.trim() || undefined, + name: saveName.trim(), + src: store.customSrc.trim(), + }) + setSaveName("") + setShowSave(false) + } + + return ( + +
+
+ + handleUrlChange(e.target.value)} + placeholder="https://example.com/stream.m3u8" + value={store.customSrc} + /> + {urlError && ( +

+ Enter a valid HTTP/HTTPS URL +

+ )} +
+
+
+ + + Reference + +
+